sync
[roojs1] / roojs-core-debug.js
1 /*
2  * Based on:
3  * Ext JS Library 1.1.1
4  * Copyright(c) 2006-2007, Ext JS, LLC.
5  *
6  * Originally Released Under LGPL - original licence link has changed is not relivant.
7  *
8  * Fork - LGPL
9  * <script type="text/javascript">
10  */
11  
12
13
14
15
16 // for old browsers
17 window["undefined"] = window["undefined"];
18
19 /**
20  * @class Roo
21  * Roo core utilities and functions.
22  * @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                );
705 /*
706  * Based on:
707  * Ext JS Library 1.1.1
708  * Copyright(c) 2006-2007, Ext JS, LLC.
709  *
710  * Originally Released Under LGPL - original licence link has changed is not relivant.
711  *
712  * Fork - LGPL
713  * <script type="text/javascript">
714  */
715
716 (function() {    
717     // wrappedn so fnCleanup is not in global scope...
718     if(Roo.isIE) {
719         function fnCleanUp() {
720             var p = Function.prototype;
721             delete p.createSequence;
722             delete p.defer;
723             delete p.createDelegate;
724             delete p.createCallback;
725             delete p.createInterceptor;
726
727             window.detachEvent("onunload", fnCleanUp);
728         }
729         window.attachEvent("onunload", fnCleanUp);
730     }
731 })();
732
733
734 /**
735  * @class Function
736  * These functions are available on every Function object (any JavaScript function).
737  */
738 Roo.apply(Function.prototype, {
739      /**
740      * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
741      * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
742      * Will create a function that is bound to those 2 args.
743      * @return {Function} The new function
744     */
745     createCallback : function(/*args...*/){
746         // make args available, in function below
747         var args = arguments;
748         var method = this;
749         return function() {
750             return method.apply(window, args);
751         };
752     },
753
754     /**
755      * Creates a delegate (callback) that sets the scope to obj.
756      * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
757      * Will create a function that is automatically scoped to this.
758      * @param {Object} obj (optional) The object for which the scope is set
759      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
760      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
761      *                                             if a number the args are inserted at the specified position
762      * @return {Function} The new function
763      */
764     createDelegate : function(obj, args, appendArgs){
765         var method = this;
766         return function() {
767             var callArgs = args || arguments;
768             if(appendArgs === true){
769                 callArgs = Array.prototype.slice.call(arguments, 0);
770                 callArgs = callArgs.concat(args);
771             }else if(typeof appendArgs == "number"){
772                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
773                 var applyArgs = [appendArgs, 0].concat(args); // create method call params
774                 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
775             }
776             return method.apply(obj || window, callArgs);
777         };
778     },
779
780     /**
781      * Calls this function after the number of millseconds specified.
782      * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
783      * @param {Object} obj (optional) The object for which the scope is set
784      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
785      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
786      *                                             if a number the args are inserted at the specified position
787      * @return {Number} The timeout id that can be used with clearTimeout
788      */
789     defer : function(millis, obj, args, appendArgs){
790         var fn = this.createDelegate(obj, args, appendArgs);
791         if(millis){
792             return setTimeout(fn, millis);
793         }
794         fn();
795         return 0;
796     },
797     /**
798      * Create a combined function call sequence of the original function + the passed function.
799      * The resulting function returns the results of the original function.
800      * The passed fcn is called with the parameters of the original function
801      * @param {Function} fcn The function to sequence
802      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
803      * @return {Function} The new function
804      */
805     createSequence : function(fcn, scope){
806         if(typeof fcn != "function"){
807             return this;
808         }
809         var method = this;
810         return function() {
811             var retval = method.apply(this || window, arguments);
812             fcn.apply(scope || this || window, arguments);
813             return retval;
814         };
815     },
816
817     /**
818      * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
819      * The resulting function returns the results of the original function.
820      * The passed fcn is called with the parameters of the original function.
821      * @addon
822      * @param {Function} fcn The function to call before the original
823      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
824      * @return {Function} The new function
825      */
826     createInterceptor : function(fcn, scope){
827         if(typeof fcn != "function"){
828             return this;
829         }
830         var method = this;
831         return function() {
832             fcn.target = this;
833             fcn.method = method;
834             if(fcn.apply(scope || this || window, arguments) === false){
835                 return;
836             }
837             return method.apply(this || window, arguments);
838         };
839     }
840 });
841 /*
842  * Based on:
843  * Ext JS Library 1.1.1
844  * Copyright(c) 2006-2007, Ext JS, LLC.
845  *
846  * Originally Released Under LGPL - original licence link has changed is not relivant.
847  *
848  * Fork - LGPL
849  * <script type="text/javascript">
850  */
851
852 Roo.applyIf(String, {
853     
854     /** @scope String */
855     
856     /**
857      * Escapes the passed string for ' and \
858      * @param {String} string The string to escape
859      * @return {String} The escaped string
860      * @static
861      */
862     escape : function(string) {
863         return string.replace(/('|\\)/g, "\\$1");
864     },
865
866     /**
867      * Pads the left side of a string with a specified character.  This is especially useful
868      * for normalizing number and date strings.  Example usage:
869      * <pre><code>
870 var s = String.leftPad('123', 5, '0');
871 // s now contains the string: '00123'
872 </code></pre>
873      * @param {String} string The original string
874      * @param {Number} size The total length of the output string
875      * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
876      * @return {String} The padded string
877      * @static
878      */
879     leftPad : function (val, size, ch) {
880         var result = new String(val);
881         if(ch === null || ch === undefined || ch === '') {
882             ch = " ";
883         }
884         while (result.length < size) {
885             result = ch + result;
886         }
887         return result;
888     },
889
890     /**
891      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
892      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
893      * <pre><code>
894 var cls = 'my-class', text = 'Some text';
895 var s = String.format('<div class="{0}">{1}</div>', cls, text);
896 // s now contains the string: '<div class="my-class">Some text</div>'
897 </code></pre>
898      * @param {String} string The tokenized string to be formatted
899      * @param {String} value1 The value to replace token {0}
900      * @param {String} value2 Etc...
901      * @return {String} The formatted string
902      * @static
903      */
904     format : function(format){
905         var args = Array.prototype.slice.call(arguments, 1);
906         return format.replace(/\{(\d+)\}/g, function(m, i){
907             return Roo.util.Format.htmlEncode(args[i]);
908         });
909     }
910   
911     
912 });
913
914 /**
915  * Utility function that allows you to easily switch a string between two alternating values.  The passed value
916  * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
917  * they are already different, the first value passed in is returned.  Note that this method returns the new value
918  * but does not change the current string.
919  * <pre><code>
920 // alternate sort directions
921 sort = sort.toggle('ASC', 'DESC');
922
923 // instead of conditional logic:
924 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
925 </code></pre>
926  * @param {String} value The value to compare to the current string
927  * @param {String} other The new value to use if the string already equals the first value passed in
928  * @return {String} The new value
929  */
930  
931 String.prototype.toggle = function(value, other){
932     return this == value ? other : value;
933 };
934
935
936 /**
937   * Remove invalid unicode characters from a string 
938   *
939   * @return {String} The clean string
940   */
941 String.prototype.unicodeClean = function () {
942     return this.replace(/[\s\S]/g,
943         function(character) {
944             if (character.charCodeAt()< 256) {
945               return character;
946            }
947            try {
948                 encodeURIComponent(character);
949            } catch(e) { 
950               return '';
951            }
952            return character;
953         }
954     );
955 };
956   
957 /*
958  * Based on:
959  * Ext JS Library 1.1.1
960  * Copyright(c) 2006-2007, Ext JS, LLC.
961  *
962  * Originally Released Under LGPL - original licence link has changed is not relivant.
963  *
964  * Fork - LGPL
965  * <script type="text/javascript">
966  */
967
968  /**
969  * @class Number
970  */
971 Roo.applyIf(Number.prototype, {
972     /**
973      * Checks whether or not the current number is within a desired range.  If the number is already within the
974      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
975      * exceeded.  Note that this method returns the constrained value but does not change the current number.
976      * @param {Number} min The minimum number in the range
977      * @param {Number} max The maximum number in the range
978      * @return {Number} The constrained value if outside the range, otherwise the current value
979      */
980     constrain : function(min, max){
981         return Math.min(Math.max(this, min), max);
982     }
983 });/*
984  * Based on:
985  * Ext JS Library 1.1.1
986  * Copyright(c) 2006-2007, Ext JS, LLC.
987  *
988  * Originally Released Under LGPL - original licence link has changed is not relivant.
989  *
990  * Fork - LGPL
991  * <script type="text/javascript">
992  */
993  /**
994  * @class Array
995  */
996 Roo.applyIf(Array.prototype, {
997     /**
998      * 
999      * Checks whether or not the specified object exists in the array.
1000      * @param {Object} o The object to check for
1001      * @return {Number} The index of o in the array (or -1 if it is not found)
1002      */
1003     indexOf : function(o){
1004        for (var i = 0, len = this.length; i < len; i++){
1005               if(this[i] == o) { return i; }
1006        }
1007            return -1;
1008     },
1009
1010     /**
1011      * Removes the specified object from the array.  If the object is not found nothing happens.
1012      * @param {Object} o The object to remove
1013      */
1014     remove : function(o){
1015        var index = this.indexOf(o);
1016        if(index != -1){
1017            this.splice(index, 1);
1018        }
1019     },
1020     /**
1021      * Map (JS 1.6 compatibility)
1022      * @param {Function} function  to call
1023      */
1024     map : function(fun )
1025     {
1026         var len = this.length >>> 0;
1027         if (typeof fun != "function") {
1028             throw new TypeError();
1029         }
1030         var res = new Array(len);
1031         var thisp = arguments[1];
1032         for (var i = 0; i < len; i++)
1033         {
1034             if (i in this) {
1035                 res[i] = fun.call(thisp, this[i], i, this);
1036             }
1037         }
1038
1039         return res;
1040     },
1041     /**
1042      * equals
1043      * @param {Array} o The array to compare to
1044      * @returns {Boolean} true if the same
1045      */
1046     equals : function(b)
1047     {
1048             // https://stackoverflow.com/questions/3115982/how-to-check-if-two-arrays-are-equal-with-javascript
1049         if (this === b) {
1050             return true;
1051         }
1052         if (b == null) {
1053             return false;
1054         }
1055         if (this.length !== b.length) {
1056             return false;
1057         }
1058           
1059         // sort?? a.sort().equals(b.sort());
1060           
1061         for (var i = 0; i < this.length; ++i) {
1062             if (this[i] !== b[i]) {
1063             return false;
1064             }
1065         }
1066         return true;
1067     } 
1068     
1069     
1070     
1071     
1072 });
1073
1074 Roo.applyIf(Array, {
1075  /**
1076      * from
1077      * @static
1078      * @param {Array} o Or Array like object (eg. nodelist)
1079      * @returns {Array} 
1080      */
1081     from : function(o)
1082     {
1083         var ret= [];
1084     
1085         for (var i =0; i < o.length; i++) { 
1086             ret[i] = o[i];
1087         }
1088         return ret;
1089       
1090     }
1091 });
1092 /*
1093  * Based on:
1094  * Ext JS Library 1.1.1
1095  * Copyright(c) 2006-2007, Ext JS, LLC.
1096  *
1097  * Originally Released Under LGPL - original licence link has changed is not relivant.
1098  *
1099  * Fork - LGPL
1100  * <script type="text/javascript">
1101  */
1102
1103 /**
1104  * @class Date
1105  *
1106  * The date parsing and format syntax is a subset of
1107  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
1108  * supported will provide results equivalent to their PHP versions.
1109  *
1110  * Following is the list of all currently supported formats:
1111  *<pre>
1112 Sample date:
1113 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1114
1115 Format  Output      Description
1116 ------  ----------  --------------------------------------------------------------
1117   d      10         Day of the month, 2 digits with leading zeros
1118   D      Wed        A textual representation of a day, three letters
1119   j      10         Day of the month without leading zeros
1120   l      Wednesday  A full textual representation of the day of the week
1121   S      th         English ordinal day of month suffix, 2 chars (use with j)
1122   w      3          Numeric representation of the day of the week
1123   z      9          The julian date, or day of the year (0-365)
1124   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1125   F      January    A full textual representation of the month
1126   m      01         Numeric representation of a month, with leading zeros
1127   M      Jan        Month name abbreviation, three letters
1128   n      1          Numeric representation of a month, without leading zeros
1129   t      31         Number of days in the given month
1130   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
1131   Y      2007       A full numeric representation of a year, 4 digits
1132   y      07         A two digit representation of a year
1133   a      pm         Lowercase Ante meridiem and Post meridiem
1134   A      PM         Uppercase Ante meridiem and Post meridiem
1135   g      3          12-hour format of an hour without leading zeros
1136   G      15         24-hour format of an hour without leading zeros
1137   h      03         12-hour format of an hour with leading zeros
1138   H      15         24-hour format of an hour with leading zeros
1139   i      05         Minutes with leading zeros
1140   s      01         Seconds, with leading zeros
1141   O      -0600      Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1142   P      -06:00     Difference to Greenwich time (GMT) with colon between hours and minutes
1143   T      CST        Timezone setting of the machine running the code
1144   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
1145 </pre>
1146  *
1147  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1148  * <pre><code>
1149 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1150 document.write(dt.format('Y-m-d'));                         //2007-01-10
1151 document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
1152 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
1153  </code></pre>
1154  *
1155  * Here are some standard date/time patterns that you might find helpful.  They
1156  * are not part of the source of Date.js, but to use them you can simply copy this
1157  * block of code into any script that is included after Date.js and they will also become
1158  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
1159  * <pre><code>
1160 Date.patterns = {
1161     ISO8601Long:"Y-m-d H:i:s",
1162     ISO8601Short:"Y-m-d",
1163     ShortDate: "n/j/Y",
1164     LongDate: "l, F d, Y",
1165     FullDateTime: "l, F d, Y g:i:s A",
1166     MonthDay: "F d",
1167     ShortTime: "g:i A",
1168     LongTime: "g:i:s A",
1169     SortableDateTime: "Y-m-d\\TH:i:s",
1170     UniversalSortableDateTime: "Y-m-d H:i:sO",
1171     YearMonth: "F, Y"
1172 };
1173 </code></pre>
1174  *
1175  * Example usage:
1176  * <pre><code>
1177 var dt = new Date();
1178 document.write(dt.format(Date.patterns.ShortDate));
1179  </code></pre>
1180  */
1181
1182 /*
1183  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1184  * They generate precompiled functions from date formats instead of parsing and
1185  * processing the pattern every time you format a date.  These functions are available
1186  * on every Date object (any javascript function).
1187  *
1188  * The original article and download are here:
1189  * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1190  *
1191  */
1192  
1193  
1194  // was in core
1195 /**
1196  Returns the number of milliseconds between this date and date
1197  @param {Date} date (optional) Defaults to now
1198  @return {Number} The diff in milliseconds
1199  @member Date getElapsed
1200  */
1201 Date.prototype.getElapsed = function(date) {
1202         return Math.abs((date || new Date()).getTime()-this.getTime());
1203 };
1204 // was in date file..
1205
1206
1207 // private
1208 Date.parseFunctions = {count:0};
1209 // private
1210 Date.parseRegexes = [];
1211 // private
1212 Date.formatFunctions = {count:0};
1213
1214 // private
1215 Date.prototype.dateFormat = function(format) {
1216     if (Date.formatFunctions[format] == null) {
1217         Date.createNewFormat(format);
1218     }
1219     var func = Date.formatFunctions[format];
1220     return this[func]();
1221 };
1222
1223
1224 /**
1225  * Formats a date given the supplied format string
1226  * @param {String} format The format string
1227  * @return {String} The formatted date
1228  * @method
1229  */
1230 Date.prototype.format = Date.prototype.dateFormat;
1231
1232 // private
1233 Date.createNewFormat = function(format) {
1234     var funcName = "format" + Date.formatFunctions.count++;
1235     Date.formatFunctions[format] = funcName;
1236     var code = "Date.prototype." + funcName + " = function(){return ";
1237     var special = false;
1238     var ch = '';
1239     for (var i = 0; i < format.length; ++i) {
1240         ch = format.charAt(i);
1241         if (!special && ch == "\\") {
1242             special = true;
1243         }
1244         else if (special) {
1245             special = false;
1246             code += "'" + String.escape(ch) + "' + ";
1247         }
1248         else {
1249             code += Date.getFormatCode(ch);
1250         }
1251     }
1252     /** eval:var:zzzzzzzzzzzzz */
1253     eval(code.substring(0, code.length - 3) + ";}");
1254 };
1255
1256 // private
1257 Date.getFormatCode = function(character) {
1258     switch (character) {
1259     case "d":
1260         return "String.leftPad(this.getDate(), 2, '0') + ";
1261     case "D":
1262         return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1263     case "j":
1264         return "this.getDate() + ";
1265     case "l":
1266         return "Date.dayNames[this.getDay()] + ";
1267     case "S":
1268         return "this.getSuffix() + ";
1269     case "w":
1270         return "this.getDay() + ";
1271     case "z":
1272         return "this.getDayOfYear() + ";
1273     case "W":
1274         return "this.getWeekOfYear() + ";
1275     case "F":
1276         return "Date.monthNames[this.getMonth()] + ";
1277     case "m":
1278         return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1279     case "M":
1280         return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1281     case "n":
1282         return "(this.getMonth() + 1) + ";
1283     case "t":
1284         return "this.getDaysInMonth() + ";
1285     case "L":
1286         return "(this.isLeapYear() ? 1 : 0) + ";
1287     case "Y":
1288         return "this.getFullYear() + ";
1289     case "y":
1290         return "('' + this.getFullYear()).substring(2, 4) + ";
1291     case "a":
1292         return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1293     case "A":
1294         return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1295     case "g":
1296         return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1297     case "G":
1298         return "this.getHours() + ";
1299     case "h":
1300         return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1301     case "H":
1302         return "String.leftPad(this.getHours(), 2, '0') + ";
1303     case "i":
1304         return "String.leftPad(this.getMinutes(), 2, '0') + ";
1305     case "s":
1306         return "String.leftPad(this.getSeconds(), 2, '0') + ";
1307     case "O":
1308         return "this.getGMTOffset() + ";
1309     case "P":
1310         return "this.getGMTColonOffset() + ";
1311     case "T":
1312         return "this.getTimezone() + ";
1313     case "Z":
1314         return "(this.getTimezoneOffset() * -60) + ";
1315     default:
1316         return "'" + String.escape(character) + "' + ";
1317     }
1318 };
1319
1320 /**
1321  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1322  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1323  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1324  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1325  * string or the parse operation will fail.
1326  * Example Usage:
1327 <pre><code>
1328 //dt = Fri May 25 2007 (current date)
1329 var dt = new Date();
1330
1331 //dt = Thu May 25 2006 (today's month/day in 2006)
1332 dt = Date.parseDate("2006", "Y");
1333
1334 //dt = Sun Jan 15 2006 (all date parts specified)
1335 dt = Date.parseDate("2006-1-15", "Y-m-d");
1336
1337 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1338 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1339 </code></pre>
1340  * @param {String} input The unparsed date as a string
1341  * @param {String} format The format the date is in
1342  * @return {Date} The parsed date
1343  * @static
1344  */
1345 Date.parseDate = function(input, format) {
1346     if (Date.parseFunctions[format] == null) {
1347         Date.createParser(format);
1348     }
1349     var func = Date.parseFunctions[format];
1350     return Date[func](input);
1351 };
1352 /**
1353  * @private
1354  */
1355
1356 Date.createParser = function(format) {
1357     var funcName = "parse" + Date.parseFunctions.count++;
1358     var regexNum = Date.parseRegexes.length;
1359     var currentGroup = 1;
1360     Date.parseFunctions[format] = funcName;
1361
1362     var code = "Date." + funcName + " = function(input){\n"
1363         + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1364         + "var d = new Date();\n"
1365         + "y = d.getFullYear();\n"
1366         + "m = d.getMonth();\n"
1367         + "d = d.getDate();\n"
1368         + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1369         + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1370         + "if (results && results.length > 0) {";
1371     var regex = "";
1372
1373     var special = false;
1374     var ch = '';
1375     for (var i = 0; i < format.length; ++i) {
1376         ch = format.charAt(i);
1377         if (!special && ch == "\\") {
1378             special = true;
1379         }
1380         else if (special) {
1381             special = false;
1382             regex += String.escape(ch);
1383         }
1384         else {
1385             var obj = Date.formatCodeToRegex(ch, currentGroup);
1386             currentGroup += obj.g;
1387             regex += obj.s;
1388             if (obj.g && obj.c) {
1389                 code += obj.c;
1390             }
1391         }
1392     }
1393
1394     code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1395         + "{v = new Date(y, m, d, h, i, s);}\n"
1396         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1397         + "{v = new Date(y, m, d, h, i);}\n"
1398         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1399         + "{v = new Date(y, m, d, h);}\n"
1400         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1401         + "{v = new Date(y, m, d);}\n"
1402         + "else if (y >= 0 && m >= 0)\n"
1403         + "{v = new Date(y, m);}\n"
1404         + "else if (y >= 0)\n"
1405         + "{v = new Date(y);}\n"
1406         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1407         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1408         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1409         + ";}";
1410
1411     Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1412     /** eval:var:zzzzzzzzzzzzz */
1413     eval(code);
1414 };
1415
1416 // private
1417 Date.formatCodeToRegex = function(character, currentGroup) {
1418     switch (character) {
1419     case "D":
1420         return {g:0,
1421         c:null,
1422         s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1423     case "j":
1424         return {g:1,
1425             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1426             s:"(\\d{1,2})"}; // day of month without leading zeroes
1427     case "d":
1428         return {g:1,
1429             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1430             s:"(\\d{2})"}; // day of month with leading zeroes
1431     case "l":
1432         return {g:0,
1433             c:null,
1434             s:"(?:" + Date.dayNames.join("|") + ")"};
1435     case "S":
1436         return {g:0,
1437             c:null,
1438             s:"(?:st|nd|rd|th)"};
1439     case "w":
1440         return {g:0,
1441             c:null,
1442             s:"\\d"};
1443     case "z":
1444         return {g:0,
1445             c:null,
1446             s:"(?:\\d{1,3})"};
1447     case "W":
1448         return {g:0,
1449             c:null,
1450             s:"(?:\\d{2})"};
1451     case "F":
1452         return {g:1,
1453             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1454             s:"(" + Date.monthNames.join("|") + ")"};
1455     case "M":
1456         return {g:1,
1457             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1458             s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1459     case "n":
1460         return {g:1,
1461             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1462             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1463     case "m":
1464         return {g:1,
1465             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1466             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1467     case "t":
1468         return {g:0,
1469             c:null,
1470             s:"\\d{1,2}"};
1471     case "L":
1472         return {g:0,
1473             c:null,
1474             s:"(?:1|0)"};
1475     case "Y":
1476         return {g:1,
1477             c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1478             s:"(\\d{4})"};
1479     case "y":
1480         return {g:1,
1481             c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1482                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1483             s:"(\\d{1,2})"};
1484     case "a":
1485         return {g:1,
1486             c:"if (results[" + currentGroup + "] == 'am') {\n"
1487                 + "if (h == 12) { h = 0; }\n"
1488                 + "} else { if (h < 12) { h += 12; }}",
1489             s:"(am|pm)"};
1490     case "A":
1491         return {g:1,
1492             c:"if (results[" + currentGroup + "] == 'AM') {\n"
1493                 + "if (h == 12) { h = 0; }\n"
1494                 + "} else { if (h < 12) { h += 12; }}",
1495             s:"(AM|PM)"};
1496     case "g":
1497     case "G":
1498         return {g:1,
1499             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1500             s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
1501     case "h":
1502     case "H":
1503         return {g:1,
1504             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1505             s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
1506     case "i":
1507         return {g:1,
1508             c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1509             s:"(\\d{2})"};
1510     case "s":
1511         return {g:1,
1512             c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1513             s:"(\\d{2})"};
1514     case "O":
1515         return {g:1,
1516             c:[
1517                 "o = results[", currentGroup, "];\n",
1518                 "var sn = o.substring(0,1);\n", // get + / - sign
1519                 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1520                 "var mn = o.substring(3,5) % 60;\n", // get minutes
1521                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1522                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1523             ].join(""),
1524             s:"([+\-]\\d{2,4})"};
1525     
1526     
1527     case "P":
1528         return {g:1,
1529                 c:[
1530                    "o = results[", currentGroup, "];\n",
1531                    "var sn = o.substring(0,1);\n",
1532                    "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1533                    "var mn = o.substring(4,6) % 60;\n",
1534                    "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1535                         "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1536             ].join(""),
1537             s:"([+\-]\\d{4})"};
1538     case "T":
1539         return {g:0,
1540             c:null,
1541             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1542     case "Z":
1543         return {g:1,
1544             c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1545                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1546             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1547     default:
1548         return {g:0,
1549             c:null,
1550             s:String.escape(character)};
1551     }
1552 };
1553
1554 /**
1555  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1556  * @return {String} The abbreviated timezone name (e.g. 'CST')
1557  */
1558 Date.prototype.getTimezone = function() {
1559     return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1560 };
1561
1562 /**
1563  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1564  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1565  */
1566 Date.prototype.getGMTOffset = function() {
1567     return (this.getTimezoneOffset() > 0 ? "-" : "+")
1568         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1569         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1570 };
1571
1572 /**
1573  * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1574  * @return {String} 2-characters representing hours and 2-characters representing minutes
1575  * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1576  */
1577 Date.prototype.getGMTColonOffset = function() {
1578         return (this.getTimezoneOffset() > 0 ? "-" : "+")
1579                 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1580                 + ":"
1581                 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1582 }
1583
1584 /**
1585  * Get the numeric day number of the year, adjusted for leap year.
1586  * @return {Number} 0 through 364 (365 in leap years)
1587  */
1588 Date.prototype.getDayOfYear = function() {
1589     var num = 0;
1590     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1591     for (var i = 0; i < this.getMonth(); ++i) {
1592         num += Date.daysInMonth[i];
1593     }
1594     return num + this.getDate() - 1;
1595 };
1596
1597 /**
1598  * Get the string representation of the numeric week number of the year
1599  * (equivalent to the format specifier 'W').
1600  * @return {String} '00' through '52'
1601  */
1602 Date.prototype.getWeekOfYear = function() {
1603     // Skip to Thursday of this week
1604     var now = this.getDayOfYear() + (4 - this.getDay());
1605     // Find the first Thursday of the year
1606     var jan1 = new Date(this.getFullYear(), 0, 1);
1607     var then = (7 - jan1.getDay() + 4);
1608     return String.leftPad(((now - then) / 7) + 1, 2, "0");
1609 };
1610
1611 /**
1612  * Whether or not the current date is in a leap year.
1613  * @return {Boolean} True if the current date is in a leap year, else false
1614  */
1615 Date.prototype.isLeapYear = function() {
1616     var year = this.getFullYear();
1617     return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1618 };
1619
1620 /**
1621  * Get the first day of the current month, adjusted for leap year.  The returned value
1622  * is the numeric day index within the week (0-6) which can be used in conjunction with
1623  * the {@link #monthNames} array to retrieve the textual day name.
1624  * Example:
1625  *<pre><code>
1626 var dt = new Date('1/10/2007');
1627 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1628 </code></pre>
1629  * @return {Number} The day number (0-6)
1630  */
1631 Date.prototype.getFirstDayOfMonth = function() {
1632     var day = (this.getDay() - (this.getDate() - 1)) % 7;
1633     return (day < 0) ? (day + 7) : day;
1634 };
1635
1636 /**
1637  * Get the last day of the current month, adjusted for leap year.  The returned value
1638  * is the numeric day index within the week (0-6) which can be used in conjunction with
1639  * the {@link #monthNames} array to retrieve the textual day name.
1640  * Example:
1641  *<pre><code>
1642 var dt = new Date('1/10/2007');
1643 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1644 </code></pre>
1645  * @return {Number} The day number (0-6)
1646  */
1647 Date.prototype.getLastDayOfMonth = function() {
1648     var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1649     return (day < 0) ? (day + 7) : day;
1650 };
1651
1652
1653 /**
1654  * Get the first date of this date's month
1655  * @return {Date}
1656  */
1657 Date.prototype.getFirstDateOfMonth = function() {
1658     return new Date(this.getFullYear(), this.getMonth(), 1);
1659 };
1660
1661 /**
1662  * Get the last date of this date's month
1663  * @return {Date}
1664  */
1665 Date.prototype.getLastDateOfMonth = function() {
1666     return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1667 };
1668 /**
1669  * Get the number of days in the current month, adjusted for leap year.
1670  * @return {Number} The number of days in the month
1671  */
1672 Date.prototype.getDaysInMonth = function() {
1673     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1674     return Date.daysInMonth[this.getMonth()];
1675 };
1676
1677 /**
1678  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1679  * @return {String} 'st, 'nd', 'rd' or 'th'
1680  */
1681 Date.prototype.getSuffix = function() {
1682     switch (this.getDate()) {
1683         case 1:
1684         case 21:
1685         case 31:
1686             return "st";
1687         case 2:
1688         case 22:
1689             return "nd";
1690         case 3:
1691         case 23:
1692             return "rd";
1693         default:
1694             return "th";
1695     }
1696 };
1697
1698 // private
1699 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1700
1701 /**
1702  * An array of textual month names.
1703  * Override these values for international dates, for example...
1704  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1705  * @type Array
1706  * @static
1707  */
1708 Date.monthNames =
1709    ["January",
1710     "February",
1711     "March",
1712     "April",
1713     "May",
1714     "June",
1715     "July",
1716     "August",
1717     "September",
1718     "October",
1719     "November",
1720     "December"];
1721
1722 /**
1723  * An array of textual day names.
1724  * Override these values for international dates, for example...
1725  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1726  * @type Array
1727  * @static
1728  */
1729 Date.dayNames =
1730    ["Sunday",
1731     "Monday",
1732     "Tuesday",
1733     "Wednesday",
1734     "Thursday",
1735     "Friday",
1736     "Saturday"];
1737
1738 // private
1739 Date.y2kYear = 50;
1740 // private
1741 Date.monthNumbers = {
1742     Jan:0,
1743     Feb:1,
1744     Mar:2,
1745     Apr:3,
1746     May:4,
1747     Jun:5,
1748     Jul:6,
1749     Aug:7,
1750     Sep:8,
1751     Oct:9,
1752     Nov:10,
1753     Dec:11};
1754
1755 /**
1756  * Creates and returns a new Date instance with the exact same date value as the called instance.
1757  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1758  * variable will also be changed.  When the intention is to create a new variable that will not
1759  * modify the original instance, you should create a clone.
1760  *
1761  * Example of correctly cloning a date:
1762  * <pre><code>
1763 //wrong way:
1764 var orig = new Date('10/1/2006');
1765 var copy = orig;
1766 copy.setDate(5);
1767 document.write(orig);  //returns 'Thu Oct 05 2006'!
1768
1769 //correct way:
1770 var orig = new Date('10/1/2006');
1771 var copy = orig.clone();
1772 copy.setDate(5);
1773 document.write(orig);  //returns 'Thu Oct 01 2006'
1774 </code></pre>
1775  * @return {Date} The new Date instance
1776  */
1777 Date.prototype.clone = function() {
1778         return new Date(this.getTime());
1779 };
1780
1781 /**
1782  * Clears any time information from this date
1783  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1784  @return {Date} this or the clone
1785  */
1786 Date.prototype.clearTime = function(clone){
1787     if(clone){
1788         return this.clone().clearTime();
1789     }
1790     this.setHours(0);
1791     this.setMinutes(0);
1792     this.setSeconds(0);
1793     this.setMilliseconds(0);
1794     return this;
1795 };
1796
1797 // private
1798 // safari setMonth is broken -- check that this is only donw once...
1799 if(Roo.isSafari && typeof(Date.brokenSetMonth) == 'undefined'){
1800     Date.brokenSetMonth = Date.prototype.setMonth;
1801         Date.prototype.setMonth = function(num){
1802                 if(num <= -1){
1803                         var n = Math.ceil(-num);
1804                         var back_year = Math.ceil(n/12);
1805                         var month = (n % 12) ? 12 - n % 12 : 0 ;
1806                         this.setFullYear(this.getFullYear() - back_year);
1807                         return Date.brokenSetMonth.call(this, month);
1808                 } else {
1809                         return Date.brokenSetMonth.apply(this, arguments);
1810                 }
1811         };
1812 }
1813
1814 /** Date interval constant 
1815 * @static 
1816 * @type String */
1817 Date.MILLI = "ms";
1818 /** Date interval constant 
1819 * @static 
1820 * @type String */
1821 Date.SECOND = "s";
1822 /** Date interval constant 
1823 * @static 
1824 * @type String */
1825 Date.MINUTE = "mi";
1826 /** Date interval constant 
1827 * @static 
1828 * @type String */
1829 Date.HOUR = "h";
1830 /** Date interval constant 
1831 * @static 
1832 * @type String */
1833 Date.DAY = "d";
1834 /** Date interval constant 
1835 * @static 
1836 * @type String */
1837 Date.MONTH = "mo";
1838 /** Date interval constant 
1839 * @static 
1840 * @type String */
1841 Date.YEAR = "y";
1842
1843 /**
1844  * Provides a convenient method of performing basic date arithmetic.  This method
1845  * does not modify the Date instance being called - it creates and returns
1846  * a new Date instance containing the resulting date value.
1847  *
1848  * Examples:
1849  * <pre><code>
1850 //Basic usage:
1851 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1852 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1853
1854 //Negative values will subtract correctly:
1855 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1856 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1857
1858 //You can even chain several calls together in one line!
1859 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1860 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1861  </code></pre>
1862  *
1863  * @param {String} interval   A valid date interval enum value
1864  * @param {Number} value      The amount to add to the current date
1865  * @return {Date} The new Date instance
1866  */
1867 Date.prototype.add = function(interval, value){
1868   var d = this.clone();
1869   if (!interval || value === 0) { return d; }
1870   switch(interval.toLowerCase()){
1871     case Date.MILLI:
1872       d.setMilliseconds(this.getMilliseconds() + value);
1873       break;
1874     case Date.SECOND:
1875       d.setSeconds(this.getSeconds() + value);
1876       break;
1877     case Date.MINUTE:
1878       d.setMinutes(this.getMinutes() + value);
1879       break;
1880     case Date.HOUR:
1881       d.setHours(this.getHours() + value);
1882       break;
1883     case Date.DAY:
1884       d.setDate(this.getDate() + value);
1885       break;
1886     case Date.MONTH:
1887       var day = this.getDate();
1888       if(day > 28){
1889           day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1890       }
1891       d.setDate(day);
1892       d.setMonth(this.getMonth() + value);
1893       break;
1894     case Date.YEAR:
1895       d.setFullYear(this.getFullYear() + value);
1896       break;
1897   }
1898   return d;
1899 };
1900 /**
1901  * @class Roo.lib.Dom
1902  * @licence LGPL
1903  * @static
1904  * 
1905  * Dom utils (from YIU afaik)
1906  *
1907  * 
1908  **/
1909 Roo.lib.Dom = {
1910     /**
1911      * Get the view width
1912      * @param {Boolean} full True will get the full document, otherwise it's the view width
1913      * @return {Number} The width
1914      */
1915      
1916     getViewWidth : function(full) {
1917         return full ? this.getDocumentWidth() : this.getViewportWidth();
1918     },
1919     /**
1920      * Get the view height
1921      * @param {Boolean} full True will get the full document, otherwise it's the view height
1922      * @return {Number} The height
1923      */
1924     getViewHeight : function(full) {
1925         return full ? this.getDocumentHeight() : this.getViewportHeight();
1926     },
1927     /**
1928      * Get the Full Document height 
1929      * @return {Number} The height
1930      */
1931     getDocumentHeight: function() {
1932         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1933         return Math.max(scrollHeight, this.getViewportHeight());
1934     },
1935     /**
1936      * Get the Full Document width
1937      * @return {Number} The width
1938      */
1939     getDocumentWidth: function() {
1940         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1941         return Math.max(scrollWidth, this.getViewportWidth());
1942     },
1943     /**
1944      * Get the Window Viewport height
1945      * @return {Number} The height
1946      */
1947     getViewportHeight: function() {
1948         var height = self.innerHeight;
1949         var mode = document.compatMode;
1950
1951         if ((mode || Roo.isIE) && !Roo.isOpera) {
1952             height = (mode == "CSS1Compat") ?
1953                      document.documentElement.clientHeight :
1954                      document.body.clientHeight;
1955         }
1956
1957         return height;
1958     },
1959     /**
1960      * Get the Window Viewport width
1961      * @return {Number} The width
1962      */
1963     getViewportWidth: function() {
1964         var width = self.innerWidth;
1965         var mode = document.compatMode;
1966
1967         if (mode || Roo.isIE) {
1968             width = (mode == "CSS1Compat") ?
1969                     document.documentElement.clientWidth :
1970                     document.body.clientWidth;
1971         }
1972         return width;
1973     },
1974
1975     isAncestor : function(p, c) {
1976         p = Roo.getDom(p);
1977         c = Roo.getDom(c);
1978         if (!p || !c) {
1979             return false;
1980         }
1981
1982         if (p.contains && !Roo.isSafari) {
1983             return p.contains(c);
1984         } else if (p.compareDocumentPosition) {
1985             return !!(p.compareDocumentPosition(c) & 16);
1986         } else {
1987             var parent = c.parentNode;
1988             while (parent) {
1989                 if (parent == p) {
1990                     return true;
1991                 }
1992                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1993                     return false;
1994                 }
1995                 parent = parent.parentNode;
1996             }
1997             return false;
1998         }
1999     },
2000
2001     getRegion : function(el) {
2002         return Roo.lib.Region.getRegion(el);
2003     },
2004
2005     getY : function(el) {
2006         return this.getXY(el)[1];
2007     },
2008
2009     getX : function(el) {
2010         return this.getXY(el)[0];
2011     },
2012
2013     getXY : function(el) {
2014         var p, pe, b, scroll, bd = document.body;
2015         el = Roo.getDom(el);
2016         var fly = Roo.lib.AnimBase.fly;
2017         if (el.getBoundingClientRect) {
2018             b = el.getBoundingClientRect();
2019             scroll = fly(document).getScroll();
2020             return [b.left + scroll.left, b.top + scroll.top];
2021         }
2022         var x = 0, y = 0;
2023
2024         p = el;
2025
2026         var hasAbsolute = fly(el).getStyle("position") == "absolute";
2027
2028         while (p) {
2029
2030             x += p.offsetLeft;
2031             y += p.offsetTop;
2032
2033             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
2034                 hasAbsolute = true;
2035             }
2036
2037             if (Roo.isGecko) {
2038                 pe = fly(p);
2039
2040                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
2041                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
2042
2043
2044                 x += bl;
2045                 y += bt;
2046
2047
2048                 if (p != el && pe.getStyle('overflow') != 'visible') {
2049                     x += bl;
2050                     y += bt;
2051                 }
2052             }
2053             p = p.offsetParent;
2054         }
2055
2056         if (Roo.isSafari && hasAbsolute) {
2057             x -= bd.offsetLeft;
2058             y -= bd.offsetTop;
2059         }
2060
2061         if (Roo.isGecko && !hasAbsolute) {
2062             var dbd = fly(bd);
2063             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
2064             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
2065         }
2066
2067         p = el.parentNode;
2068         while (p && p != bd) {
2069             if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
2070                 x -= p.scrollLeft;
2071                 y -= p.scrollTop;
2072             }
2073             p = p.parentNode;
2074         }
2075         return [x, y];
2076     },
2077  
2078   
2079
2080
2081     setXY : function(el, xy) {
2082         el = Roo.fly(el, '_setXY');
2083         el.position();
2084         var pts = el.translatePoints(xy);
2085         if (xy[0] !== false) {
2086             el.dom.style.left = pts.left + "px";
2087         }
2088         if (xy[1] !== false) {
2089             el.dom.style.top = pts.top + "px";
2090         }
2091     },
2092
2093     setX : function(el, x) {
2094         this.setXY(el, [x, false]);
2095     },
2096
2097     setY : function(el, y) {
2098         this.setXY(el, [false, y]);
2099     }
2100 };
2101 /*
2102  * Portions of this file are based on pieces of Yahoo User Interface Library
2103  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2104  * YUI licensed under the BSD License:
2105  * http://developer.yahoo.net/yui/license.txt
2106  * <script type="text/javascript">
2107  *
2108  */
2109
2110 Roo.lib.Event = function() {
2111     var loadComplete = false;
2112     var listeners = [];
2113     var unloadListeners = [];
2114     var retryCount = 0;
2115     var onAvailStack = [];
2116     var counter = 0;
2117     var lastError = null;
2118
2119     return {
2120         POLL_RETRYS: 200,
2121         POLL_INTERVAL: 20,
2122         EL: 0,
2123         TYPE: 1,
2124         FN: 2,
2125         WFN: 3,
2126         OBJ: 3,
2127         ADJ_SCOPE: 4,
2128         _interval: null,
2129
2130         startInterval: function() {
2131             if (!this._interval) {
2132                 var self = this;
2133                 var callback = function() {
2134                     self._tryPreloadAttach();
2135                 };
2136                 this._interval = setInterval(callback, this.POLL_INTERVAL);
2137
2138             }
2139         },
2140
2141         onAvailable: function(p_id, p_fn, p_obj, p_override) {
2142             onAvailStack.push({ id:         p_id,
2143                 fn:         p_fn,
2144                 obj:        p_obj,
2145                 override:   p_override,
2146                 checkReady: false    });
2147
2148             retryCount = this.POLL_RETRYS;
2149             this.startInterval();
2150         },
2151
2152
2153         addListener: function(el, eventName, fn) {
2154             el = Roo.getDom(el);
2155             if (!el || !fn) {
2156                 return false;
2157             }
2158
2159             if ("unload" == eventName) {
2160                 unloadListeners[unloadListeners.length] =
2161                 [el, eventName, fn];
2162                 return true;
2163             }
2164
2165             var wrappedFn = function(e) {
2166                 return fn(Roo.lib.Event.getEvent(e));
2167             };
2168
2169             var li = [el, eventName, fn, wrappedFn];
2170
2171             var index = listeners.length;
2172             listeners[index] = li;
2173
2174             this.doAdd(el, eventName, wrappedFn, false);
2175             return true;
2176
2177         },
2178
2179
2180         removeListener: function(el, eventName, fn) {
2181             var i, len;
2182
2183             el = Roo.getDom(el);
2184
2185             if(!fn) {
2186                 return this.purgeElement(el, false, eventName);
2187             }
2188
2189
2190             if ("unload" == eventName) {
2191
2192                 for (i = 0,len = unloadListeners.length; i < len; i++) {
2193                     var li = unloadListeners[i];
2194                     if (li &&
2195                         li[0] == el &&
2196                         li[1] == eventName &&
2197                         li[2] == fn) {
2198                         unloadListeners.splice(i, 1);
2199                         return true;
2200                     }
2201                 }
2202
2203                 return false;
2204             }
2205
2206             var cacheItem = null;
2207
2208
2209             var index = arguments[3];
2210
2211             if ("undefined" == typeof index) {
2212                 index = this._getCacheIndex(el, eventName, fn);
2213             }
2214
2215             if (index >= 0) {
2216                 cacheItem = listeners[index];
2217             }
2218
2219             if (!el || !cacheItem) {
2220                 return false;
2221             }
2222
2223             this.doRemove(el, eventName, cacheItem[this.WFN], false);
2224
2225             delete listeners[index][this.WFN];
2226             delete listeners[index][this.FN];
2227             listeners.splice(index, 1);
2228
2229             return true;
2230
2231         },
2232
2233
2234         getTarget: function(ev, resolveTextNode) {
2235             ev = ev.browserEvent || ev;
2236             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2237             var t = ev.target || ev.srcElement;
2238             return this.resolveTextNode(t);
2239         },
2240
2241
2242         resolveTextNode: function(node) {
2243             if (Roo.isSafari && node && 3 == node.nodeType) {
2244                 return node.parentNode;
2245             } else {
2246                 return node;
2247             }
2248         },
2249
2250
2251         getPageX: function(ev) {
2252             ev = ev.browserEvent || ev;
2253             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2254             var x = ev.pageX;
2255             if (!x && 0 !== x) {
2256                 x = ev.clientX || 0;
2257
2258                 if (Roo.isIE) {
2259                     x += this.getScroll()[1];
2260                 }
2261             }
2262
2263             return x;
2264         },
2265
2266
2267         getPageY: function(ev) {
2268             ev = ev.browserEvent || ev;
2269             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2270             var y = ev.pageY;
2271             if (!y && 0 !== y) {
2272                 y = ev.clientY || 0;
2273
2274                 if (Roo.isIE) {
2275                     y += this.getScroll()[0];
2276                 }
2277             }
2278
2279
2280             return y;
2281         },
2282
2283
2284         getXY: function(ev) {
2285             ev = ev.browserEvent || ev;
2286             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2287             return [this.getPageX(ev), this.getPageY(ev)];
2288         },
2289
2290
2291         getRelatedTarget: function(ev) {
2292             ev = ev.browserEvent || ev;
2293             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2294             var t = ev.relatedTarget;
2295             if (!t) {
2296                 if (ev.type == "mouseout") {
2297                     t = ev.toElement;
2298                 } else if (ev.type == "mouseover") {
2299                     t = ev.fromElement;
2300                 }
2301             }
2302
2303             return this.resolveTextNode(t);
2304         },
2305
2306
2307         getTime: function(ev) {
2308             ev = ev.browserEvent || ev;
2309             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2310             if (!ev.time) {
2311                 var t = new Date().getTime();
2312                 try {
2313                     ev.time = t;
2314                 } catch(ex) {
2315                     this.lastError = ex;
2316                     return t;
2317                 }
2318             }
2319
2320             return ev.time;
2321         },
2322
2323
2324         stopEvent: function(ev) {
2325             this.stopPropagation(ev);
2326             this.preventDefault(ev);
2327         },
2328
2329
2330         stopPropagation: function(ev) {
2331             ev = ev.browserEvent || ev;
2332             if (ev.stopPropagation) {
2333                 ev.stopPropagation();
2334             } else {
2335                 ev.cancelBubble = true;
2336             }
2337         },
2338
2339
2340         preventDefault: function(ev) {
2341             ev = ev.browserEvent || ev;
2342             if(ev.preventDefault) {
2343                 ev.preventDefault();
2344             } else {
2345                 ev.returnValue = false;
2346             }
2347         },
2348
2349
2350         getEvent: function(e) {
2351             var ev = e || window.event;
2352             if (!ev) {
2353                 var c = this.getEvent.caller;
2354                 while (c) {
2355                     ev = c.arguments[0];
2356                     if (ev && Event == ev.constructor) {
2357                         break;
2358                     }
2359                     c = c.caller;
2360                 }
2361             }
2362             return ev;
2363         },
2364
2365
2366         getCharCode: function(ev) {
2367             ev = ev.browserEvent || ev;
2368             return ev.charCode || ev.keyCode || 0;
2369         },
2370
2371
2372         _getCacheIndex: function(el, eventName, fn) {
2373             for (var i = 0,len = listeners.length; i < len; ++i) {
2374                 var li = listeners[i];
2375                 if (li &&
2376                     li[this.FN] == fn &&
2377                     li[this.EL] == el &&
2378                     li[this.TYPE] == eventName) {
2379                     return i;
2380                 }
2381             }
2382
2383             return -1;
2384         },
2385
2386
2387         elCache: {},
2388
2389
2390         getEl: function(id) {
2391             return document.getElementById(id);
2392         },
2393
2394
2395         clearCache: function() {
2396         },
2397
2398
2399         _load: function(e) {
2400             loadComplete = true;
2401             var EU = Roo.lib.Event;
2402
2403
2404             if (Roo.isIE) {
2405                 EU.doRemove(window, "load", EU._load);
2406             }
2407         },
2408
2409
2410         _tryPreloadAttach: function() {
2411
2412             if (this.locked) {
2413                 return false;
2414             }
2415
2416             this.locked = true;
2417
2418
2419             var tryAgain = !loadComplete;
2420             if (!tryAgain) {
2421                 tryAgain = (retryCount > 0);
2422             }
2423
2424
2425             var notAvail = [];
2426             for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2427                 var item = onAvailStack[i];
2428                 if (item) {
2429                     var el = this.getEl(item.id);
2430
2431                     if (el) {
2432                         if (!item.checkReady ||
2433                             loadComplete ||
2434                             el.nextSibling ||
2435                             (document && document.body)) {
2436
2437                             var scope = el;
2438                             if (item.override) {
2439                                 if (item.override === true) {
2440                                     scope = item.obj;
2441                                 } else {
2442                                     scope = item.override;
2443                                 }
2444                             }
2445                             item.fn.call(scope, item.obj);
2446                             onAvailStack[i] = null;
2447                         }
2448                     } else {
2449                         notAvail.push(item);
2450                     }
2451                 }
2452             }
2453
2454             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2455
2456             if (tryAgain) {
2457
2458                 this.startInterval();
2459             } else {
2460                 clearInterval(this._interval);
2461                 this._interval = null;
2462             }
2463
2464             this.locked = false;
2465
2466             return true;
2467
2468         },
2469
2470
2471         purgeElement: function(el, recurse, eventName) {
2472             var elListeners = this.getListeners(el, eventName);
2473             if (elListeners) {
2474                 for (var i = 0,len = elListeners.length; i < len; ++i) {
2475                     var l = elListeners[i];
2476                     this.removeListener(el, l.type, l.fn);
2477                 }
2478             }
2479
2480             if (recurse && el && el.childNodes) {
2481                 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2482                     this.purgeElement(el.childNodes[i], recurse, eventName);
2483                 }
2484             }
2485         },
2486
2487
2488         getListeners: function(el, eventName) {
2489             var results = [], searchLists;
2490             if (!eventName) {
2491                 searchLists = [listeners, unloadListeners];
2492             } else if (eventName == "unload") {
2493                 searchLists = [unloadListeners];
2494             } else {
2495                 searchLists = [listeners];
2496             }
2497
2498             for (var j = 0; j < searchLists.length; ++j) {
2499                 var searchList = searchLists[j];
2500                 if (searchList && searchList.length > 0) {
2501                     for (var i = 0,len = searchList.length; i < len; ++i) {
2502                         var l = searchList[i];
2503                         if (l && l[this.EL] === el &&
2504                             (!eventName || eventName === l[this.TYPE])) {
2505                             results.push({
2506                                 type:   l[this.TYPE],
2507                                 fn:     l[this.FN],
2508                                 obj:    l[this.OBJ],
2509                                 adjust: l[this.ADJ_SCOPE],
2510                                 index:  i
2511                             });
2512                         }
2513                     }
2514                 }
2515             }
2516
2517             return (results.length) ? results : null;
2518         },
2519
2520
2521         _unload: function(e) {
2522
2523             var EU = Roo.lib.Event, i, j, l, len, index;
2524
2525             for (i = 0,len = unloadListeners.length; i < len; ++i) {
2526                 l = unloadListeners[i];
2527                 if (l) {
2528                     var scope = window;
2529                     if (l[EU.ADJ_SCOPE]) {
2530                         if (l[EU.ADJ_SCOPE] === true) {
2531                             scope = l[EU.OBJ];
2532                         } else {
2533                             scope = l[EU.ADJ_SCOPE];
2534                         }
2535                     }
2536                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2537                     unloadListeners[i] = null;
2538                     l = null;
2539                     scope = null;
2540                 }
2541             }
2542
2543             unloadListeners = null;
2544
2545             if (listeners && listeners.length > 0) {
2546                 j = listeners.length;
2547                 while (j) {
2548                     index = j - 1;
2549                     l = listeners[index];
2550                     if (l) {
2551                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2552                                 l[EU.FN], index);
2553                     }
2554                     j = j - 1;
2555                 }
2556                 l = null;
2557
2558                 EU.clearCache();
2559             }
2560
2561             EU.doRemove(window, "unload", EU._unload);
2562
2563         },
2564
2565
2566         getScroll: function() {
2567             var dd = document.documentElement, db = document.body;
2568             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2569                 return [dd.scrollTop, dd.scrollLeft];
2570             } else if (db) {
2571                 return [db.scrollTop, db.scrollLeft];
2572             } else {
2573                 return [0, 0];
2574             }
2575         },
2576
2577
2578         doAdd: function () {
2579             if (window.addEventListener) {
2580                 return function(el, eventName, fn, capture) {
2581                     el.addEventListener(eventName, fn, (capture));
2582                 };
2583             } else if (window.attachEvent) {
2584                 return function(el, eventName, fn, capture) {
2585                     el.attachEvent("on" + eventName, fn);
2586                 };
2587             } else {
2588                 return function() {
2589                 };
2590             }
2591         }(),
2592
2593
2594         doRemove: function() {
2595             if (window.removeEventListener) {
2596                 return function (el, eventName, fn, capture) {
2597                     el.removeEventListener(eventName, fn, (capture));
2598                 };
2599             } else if (window.detachEvent) {
2600                 return function (el, eventName, fn) {
2601                     el.detachEvent("on" + eventName, fn);
2602                 };
2603             } else {
2604                 return function() {
2605                 };
2606             }
2607         }()
2608     };
2609     
2610 }();
2611 (function() {     
2612    
2613     var E = Roo.lib.Event;
2614     E.on = E.addListener;
2615     E.un = E.removeListener;
2616
2617     if (document && document.body) {
2618         E._load();
2619     } else {
2620         E.doAdd(window, "load", E._load);
2621     }
2622     E.doAdd(window, "unload", E._unload);
2623     E._tryPreloadAttach();
2624 })();
2625
2626  
2627
2628 (function() {
2629     /**
2630      * @class Roo.lib.Ajax
2631      *
2632      * provide a simple Ajax request utility functions
2633      * 
2634      * Portions of this file are based on pieces of Yahoo User Interface Library
2635     * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2636     * YUI licensed under the BSD License:
2637     * http://developer.yahoo.net/yui/license.txt
2638     * <script type="text/javascript">
2639     *
2640      *
2641      */
2642     Roo.lib.Ajax = {
2643         /**
2644          * @static 
2645          */
2646         request : function(method, uri, cb, data, options) {
2647             if(options){
2648                 var hs = options.headers;
2649                 if(hs){
2650                     for(var h in hs){
2651                         if(hs.hasOwnProperty(h)){
2652                             this.initHeader(h, hs[h], false);
2653                         }
2654                     }
2655                 }
2656                 if(options.xmlData){
2657                     this.initHeader('Content-Type', 'text/xml', false);
2658                     method = 'POST';
2659                     data = options.xmlData;
2660                 }
2661             }
2662
2663             return this.asyncRequest(method, uri, cb, data);
2664         },
2665         /**
2666          * serialize a form
2667          *
2668          * @static
2669          * @param {DomForm} form element
2670          * @return {String} urlencode form output.
2671          */
2672         serializeForm : function(form) {
2673             if(typeof form == 'string') {
2674                 form = (document.getElementById(form) || document.forms[form]);
2675             }
2676
2677             var el, name, val, disabled, data = '', hasSubmit = false;
2678             for (var i = 0; i < form.elements.length; i++) {
2679                 el = form.elements[i];
2680                 disabled = form.elements[i].disabled;
2681                 name = form.elements[i].name;
2682                 val = form.elements[i].value;
2683
2684                 if (!disabled && name){
2685                     switch (el.type)
2686                             {
2687                         case 'select-one':
2688                         case 'select-multiple':
2689                             for (var j = 0; j < el.options.length; j++) {
2690                                 if (el.options[j].selected) {
2691                                     if (Roo.isIE) {
2692                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2693                                     }
2694                                     else {
2695                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2696                                     }
2697                                 }
2698                             }
2699                             break;
2700                         case 'radio':
2701                         case 'checkbox':
2702                             if (el.checked) {
2703                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2704                             }
2705                             break;
2706                         case 'file':
2707
2708                         case undefined:
2709
2710                         case 'reset':
2711
2712                         case 'button':
2713
2714                             break;
2715                         case 'submit':
2716                             if(hasSubmit == false) {
2717                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2718                                 hasSubmit = true;
2719                             }
2720                             break;
2721                         default:
2722                             data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2723                             break;
2724                     }
2725                 }
2726             }
2727             data = data.substr(0, data.length - 1);
2728             return data;
2729         },
2730
2731         headers:{},
2732
2733         hasHeaders:false,
2734
2735         useDefaultHeader:true,
2736
2737         defaultPostHeader:'application/x-www-form-urlencoded',
2738
2739         useDefaultXhrHeader:true,
2740
2741         defaultXhrHeader:'XMLHttpRequest',
2742
2743         hasDefaultHeaders:true,
2744
2745         defaultHeaders:{},
2746
2747         poll:{},
2748
2749         timeout:{},
2750
2751         pollInterval:50,
2752
2753         transactionId:0,
2754
2755         setProgId:function(id)
2756         {
2757             this.activeX.unshift(id);
2758         },
2759
2760         setDefaultPostHeader:function(b)
2761         {
2762             this.useDefaultHeader = b;
2763         },
2764
2765         setDefaultXhrHeader:function(b)
2766         {
2767             this.useDefaultXhrHeader = b;
2768         },
2769
2770         setPollingInterval:function(i)
2771         {
2772             if (typeof i == 'number' && isFinite(i)) {
2773                 this.pollInterval = i;
2774             }
2775         },
2776
2777         createXhrObject:function(transactionId)
2778         {
2779             var obj,http;
2780             try
2781             {
2782
2783                 http = new XMLHttpRequest();
2784
2785                 obj = { conn:http, tId:transactionId };
2786             }
2787             catch(e)
2788             {
2789                 for (var i = 0; i < this.activeX.length; ++i) {
2790                     try
2791                     {
2792
2793                         http = new ActiveXObject(this.activeX[i]);
2794
2795                         obj = { conn:http, tId:transactionId };
2796                         break;
2797                     }
2798                     catch(e) {
2799                     }
2800                 }
2801             }
2802             finally
2803             {
2804                 return obj;
2805             }
2806         },
2807
2808         getConnectionObject:function()
2809         {
2810             var o;
2811             var tId = this.transactionId;
2812
2813             try
2814             {
2815                 o = this.createXhrObject(tId);
2816                 if (o) {
2817                     this.transactionId++;
2818                 }
2819             }
2820             catch(e) {
2821             }
2822             finally
2823             {
2824                 return o;
2825             }
2826         },
2827
2828         asyncRequest:function(method, uri, callback, postData)
2829         {
2830             var o = this.getConnectionObject();
2831
2832             if (!o) {
2833                 return null;
2834             }
2835             else {
2836                 o.conn.open(method, uri, true);
2837
2838                 if (this.useDefaultXhrHeader) {
2839                     if (!this.defaultHeaders['X-Requested-With']) {
2840                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2841                     }
2842                 }
2843
2844                 if(postData && this.useDefaultHeader){
2845                     this.initHeader('Content-Type', this.defaultPostHeader);
2846                 }
2847
2848                  if (this.hasDefaultHeaders || this.hasHeaders) {
2849                     this.setHeader(o);
2850                 }
2851
2852                 this.handleReadyState(o, callback);
2853                 o.conn.send(postData || null);
2854
2855                 return o;
2856             }
2857         },
2858
2859         handleReadyState:function(o, callback)
2860         {
2861             var oConn = this;
2862
2863             if (callback && callback.timeout) {
2864                 
2865                 this.timeout[o.tId] = window.setTimeout(function() {
2866                     oConn.abort(o, callback, true);
2867                 }, callback.timeout);
2868             }
2869
2870             this.poll[o.tId] = window.setInterval(
2871                     function() {
2872                         if (o.conn && o.conn.readyState == 4) {
2873                             window.clearInterval(oConn.poll[o.tId]);
2874                             delete oConn.poll[o.tId];
2875
2876                             if(callback && callback.timeout) {
2877                                 window.clearTimeout(oConn.timeout[o.tId]);
2878                                 delete oConn.timeout[o.tId];
2879                             }
2880
2881                             oConn.handleTransactionResponse(o, callback);
2882                         }
2883                     }
2884                     , this.pollInterval);
2885         },
2886
2887         handleTransactionResponse:function(o, callback, isAbort)
2888         {
2889
2890             if (!callback) {
2891                 this.releaseObject(o);
2892                 return;
2893             }
2894
2895             var httpStatus, responseObject;
2896
2897             try
2898             {
2899                 if (o.conn.status !== undefined && o.conn.status != 0) {
2900                     httpStatus = o.conn.status;
2901                 }
2902                 else {
2903                     httpStatus = 13030;
2904                 }
2905             }
2906             catch(e) {
2907
2908
2909                 httpStatus = 13030;
2910             }
2911
2912             if (httpStatus >= 200 && httpStatus < 300) {
2913                 responseObject = this.createResponseObject(o, callback.argument);
2914                 if (callback.success) {
2915                     if (!callback.scope) {
2916                         callback.success(responseObject);
2917                     }
2918                     else {
2919
2920
2921                         callback.success.apply(callback.scope, [responseObject]);
2922                     }
2923                 }
2924             }
2925             else {
2926                 switch (httpStatus) {
2927
2928                     case 12002:
2929                     case 12029:
2930                     case 12030:
2931                     case 12031:
2932                     case 12152:
2933                     case 13030:
2934                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2935                         if (callback.failure) {
2936                             if (!callback.scope) {
2937                                 callback.failure(responseObject);
2938                             }
2939                             else {
2940                                 callback.failure.apply(callback.scope, [responseObject]);
2941                             }
2942                         }
2943                         break;
2944                     default:
2945                         responseObject = this.createResponseObject(o, callback.argument);
2946                         if (callback.failure) {
2947                             if (!callback.scope) {
2948                                 callback.failure(responseObject);
2949                             }
2950                             else {
2951                                 callback.failure.apply(callback.scope, [responseObject]);
2952                             }
2953                         }
2954                 }
2955             }
2956
2957             this.releaseObject(o);
2958             responseObject = null;
2959         },
2960
2961         createResponseObject:function(o, callbackArg)
2962         {
2963             var obj = {};
2964             var headerObj = {};
2965
2966             try
2967             {
2968                 var headerStr = o.conn.getAllResponseHeaders();
2969                 var header = headerStr.split('\n');
2970                 for (var i = 0; i < header.length; i++) {
2971                     var delimitPos = header[i].indexOf(':');
2972                     if (delimitPos != -1) {
2973                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2974                     }
2975                 }
2976             }
2977             catch(e) {
2978             }
2979
2980             obj.tId = o.tId;
2981             obj.status = o.conn.status;
2982             obj.statusText = o.conn.statusText;
2983             obj.getResponseHeader = headerObj;
2984             obj.getAllResponseHeaders = headerStr;
2985             obj.responseText = o.conn.responseText;
2986             obj.responseXML = o.conn.responseXML;
2987
2988             if (typeof callbackArg !== undefined) {
2989                 obj.argument = callbackArg;
2990             }
2991
2992             return obj;
2993         },
2994
2995         createExceptionObject:function(tId, callbackArg, isAbort)
2996         {
2997             var COMM_CODE = 0;
2998             var COMM_ERROR = 'communication failure';
2999             var ABORT_CODE = -1;
3000             var ABORT_ERROR = 'transaction aborted';
3001
3002             var obj = {};
3003
3004             obj.tId = tId;
3005             if (isAbort) {
3006                 obj.status = ABORT_CODE;
3007                 obj.statusText = ABORT_ERROR;
3008             }
3009             else {
3010                 obj.status = COMM_CODE;
3011                 obj.statusText = COMM_ERROR;
3012             }
3013
3014             if (callbackArg) {
3015                 obj.argument = callbackArg;
3016             }
3017
3018             return obj;
3019         },
3020
3021         initHeader:function(label, value, isDefault)
3022         {
3023             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
3024
3025             if (headerObj[label] === undefined) {
3026                 headerObj[label] = value;
3027             }
3028             else {
3029
3030
3031                 headerObj[label] = value + "," + headerObj[label];
3032             }
3033
3034             if (isDefault) {
3035                 this.hasDefaultHeaders = true;
3036             }
3037             else {
3038                 this.hasHeaders = true;
3039             }
3040         },
3041
3042
3043         setHeader:function(o)
3044         {
3045             if (this.hasDefaultHeaders) {
3046                 for (var prop in this.defaultHeaders) {
3047                     if (this.defaultHeaders.hasOwnProperty(prop)) {
3048                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
3049                     }
3050                 }
3051             }
3052
3053             if (this.hasHeaders) {
3054                 for (var prop in this.headers) {
3055                     if (this.headers.hasOwnProperty(prop)) {
3056                         o.conn.setRequestHeader(prop, this.headers[prop]);
3057                     }
3058                 }
3059                 this.headers = {};
3060                 this.hasHeaders = false;
3061             }
3062         },
3063
3064         resetDefaultHeaders:function() {
3065             delete this.defaultHeaders;
3066             this.defaultHeaders = {};
3067             this.hasDefaultHeaders = false;
3068         },
3069
3070         abort:function(o, callback, isTimeout)
3071         {
3072             if(this.isCallInProgress(o)) {
3073                 o.conn.abort();
3074                 window.clearInterval(this.poll[o.tId]);
3075                 delete this.poll[o.tId];
3076                 if (isTimeout) {
3077                     delete this.timeout[o.tId];
3078                 }
3079
3080                 this.handleTransactionResponse(o, callback, true);
3081
3082                 return true;
3083             }
3084             else {
3085                 return false;
3086             }
3087         },
3088
3089
3090         isCallInProgress:function(o)
3091         {
3092             if (o && o.conn) {
3093                 return o.conn.readyState != 4 && o.conn.readyState != 0;
3094             }
3095             else {
3096
3097                 return false;
3098             }
3099         },
3100
3101
3102         releaseObject:function(o)
3103         {
3104
3105             o.conn = null;
3106
3107             o = null;
3108         },
3109
3110         activeX:[
3111         'MSXML2.XMLHTTP.3.0',
3112         'MSXML2.XMLHTTP',
3113         'Microsoft.XMLHTTP'
3114         ]
3115
3116
3117     };
3118 })();/*
3119  * Portions of this file are based on pieces of Yahoo User Interface Library
3120  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3121  * YUI licensed under the BSD License:
3122  * http://developer.yahoo.net/yui/license.txt
3123  * <script type="text/javascript">
3124  *
3125  */
3126
3127 Roo.lib.Region = function(t, r, b, l) {
3128     this.top = t;
3129     this[1] = t;
3130     this.right = r;
3131     this.bottom = b;
3132     this.left = l;
3133     this[0] = l;
3134 };
3135
3136
3137 Roo.lib.Region.prototype = {
3138     contains : function(region) {
3139         return ( region.left >= this.left &&
3140                  region.right <= this.right &&
3141                  region.top >= this.top &&
3142                  region.bottom <= this.bottom    );
3143
3144     },
3145
3146     getArea : function() {
3147         return ( (this.bottom - this.top) * (this.right - this.left) );
3148     },
3149
3150     intersect : function(region) {
3151         var t = Math.max(this.top, region.top);
3152         var r = Math.min(this.right, region.right);
3153         var b = Math.min(this.bottom, region.bottom);
3154         var l = Math.max(this.left, region.left);
3155
3156         if (b >= t && r >= l) {
3157             return new Roo.lib.Region(t, r, b, l);
3158         } else {
3159             return null;
3160         }
3161     },
3162     union : function(region) {
3163         var t = Math.min(this.top, region.top);
3164         var r = Math.max(this.right, region.right);
3165         var b = Math.max(this.bottom, region.bottom);
3166         var l = Math.min(this.left, region.left);
3167
3168         return new Roo.lib.Region(t, r, b, l);
3169     },
3170
3171     adjust : function(t, l, b, r) {
3172         this.top += t;
3173         this.left += l;
3174         this.right += r;
3175         this.bottom += b;
3176         return this;
3177     }
3178 };
3179
3180 Roo.lib.Region.getRegion = function(el) {
3181     var p = Roo.lib.Dom.getXY(el);
3182
3183     var t = p[1];
3184     var r = p[0] + el.offsetWidth;
3185     var b = p[1] + el.offsetHeight;
3186     var l = p[0];
3187
3188     return new Roo.lib.Region(t, r, b, l);
3189 };
3190 /*
3191  * Portions of this file are based on pieces of Yahoo User Interface Library
3192  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3193  * YUI licensed under the BSD License:
3194  * http://developer.yahoo.net/yui/license.txt
3195  * <script type="text/javascript">
3196  *
3197  */
3198 //@@dep Roo.lib.Region
3199
3200
3201 Roo.lib.Point = function(x, y) {
3202     if (x instanceof Array) {
3203         y = x[1];
3204         x = x[0];
3205     }
3206     this.x = this.right = this.left = this[0] = x;
3207     this.y = this.top = this.bottom = this[1] = y;
3208 };
3209
3210 Roo.lib.Point.prototype = new Roo.lib.Region();
3211 /*
3212  * Portions of this file are based on pieces of Yahoo User Interface Library
3213  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3214  * YUI licensed under the BSD License:
3215  * http://developer.yahoo.net/yui/license.txt
3216  * <script type="text/javascript">
3217  *
3218  */
3219  
3220 (function() {   
3221
3222     Roo.lib.Anim = {
3223         scroll : function(el, args, duration, easing, cb, scope) {
3224             this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3225         },
3226
3227         motion : function(el, args, duration, easing, cb, scope) {
3228             this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3229         },
3230
3231         color : function(el, args, duration, easing, cb, scope) {
3232             this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3233         },
3234
3235         run : function(el, args, duration, easing, cb, scope, type) {
3236             type = type || Roo.lib.AnimBase;
3237             if (typeof easing == "string") {
3238                 easing = Roo.lib.Easing[easing];
3239             }
3240             var anim = new type(el, args, duration, easing);
3241             anim.animateX(function() {
3242                 Roo.callback(cb, scope);
3243             });
3244             return anim;
3245         }
3246     };
3247 })();/*
3248  * Portions of this file are based on pieces of Yahoo User Interface Library
3249  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3250  * YUI licensed under the BSD License:
3251  * http://developer.yahoo.net/yui/license.txt
3252  * <script type="text/javascript">
3253  *
3254  */
3255
3256 (function() {    
3257     var libFlyweight;
3258     
3259     function fly(el) {
3260         if (!libFlyweight) {
3261             libFlyweight = new Roo.Element.Flyweight();
3262         }
3263         libFlyweight.dom = el;
3264         return libFlyweight;
3265     }
3266
3267     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3268     
3269    
3270     
3271     Roo.lib.AnimBase = function(el, attributes, duration, method) {
3272         if (el) {
3273             this.init(el, attributes, duration, method);
3274         }
3275     };
3276
3277     Roo.lib.AnimBase.fly = fly;
3278     
3279     
3280     
3281     Roo.lib.AnimBase.prototype = {
3282
3283         toString: function() {
3284             var el = this.getEl();
3285             var id = el.id || el.tagName;
3286             return ("Anim " + id);
3287         },
3288
3289         patterns: {
3290             noNegatives:        /width|height|opacity|padding/i,
3291             offsetAttribute:  /^((width|height)|(top|left))$/,
3292             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
3293             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3294         },
3295
3296
3297         doMethod: function(attr, start, end) {
3298             return this.method(this.currentFrame, start, end - start, this.totalFrames);
3299         },
3300
3301
3302         setAttribute: function(attr, val, unit) {
3303             if (this.patterns.noNegatives.test(attr)) {
3304                 val = (val > 0) ? val : 0;
3305             }
3306
3307             Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3308         },
3309
3310
3311         getAttribute: function(attr) {
3312             var el = this.getEl();
3313             var val = fly(el).getStyle(attr);
3314
3315             if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3316                 return parseFloat(val);
3317             }
3318
3319             var a = this.patterns.offsetAttribute.exec(attr) || [];
3320             var pos = !!( a[3] );
3321             var box = !!( a[2] );
3322
3323
3324             if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3325                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3326             } else {
3327                 val = 0;
3328             }
3329
3330             return val;
3331         },
3332
3333
3334         getDefaultUnit: function(attr) {
3335             if (this.patterns.defaultUnit.test(attr)) {
3336                 return 'px';
3337             }
3338
3339             return '';
3340         },
3341
3342         animateX : function(callback, scope) {
3343             var f = function() {
3344                 this.onComplete.removeListener(f);
3345                 if (typeof callback == "function") {
3346                     callback.call(scope || this, this);
3347                 }
3348             };
3349             this.onComplete.addListener(f, this);
3350             this.animate();
3351         },
3352
3353
3354         setRuntimeAttribute: function(attr) {
3355             var start;
3356             var end;
3357             var attributes = this.attributes;
3358
3359             this.runtimeAttributes[attr] = {};
3360
3361             var isset = function(prop) {
3362                 return (typeof prop !== 'undefined');
3363             };
3364
3365             if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3366                 return false;
3367             }
3368
3369             start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3370
3371
3372             if (isset(attributes[attr]['to'])) {
3373                 end = attributes[attr]['to'];
3374             } else if (isset(attributes[attr]['by'])) {
3375                 if (start.constructor == Array) {
3376                     end = [];
3377                     for (var i = 0, len = start.length; i < len; ++i) {
3378                         end[i] = start[i] + attributes[attr]['by'][i];
3379                     }
3380                 } else {
3381                     end = start + attributes[attr]['by'];
3382                 }
3383             }
3384
3385             this.runtimeAttributes[attr].start = start;
3386             this.runtimeAttributes[attr].end = end;
3387
3388
3389             this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3390         },
3391
3392
3393         init: function(el, attributes, duration, method) {
3394
3395             var isAnimated = false;
3396
3397
3398             var startTime = null;
3399
3400
3401             var actualFrames = 0;
3402
3403
3404             el = Roo.getDom(el);
3405
3406
3407             this.attributes = attributes || {};
3408
3409
3410             this.duration = duration || 1;
3411
3412
3413             this.method = method || Roo.lib.Easing.easeNone;
3414
3415
3416             this.useSeconds = true;
3417
3418
3419             this.currentFrame = 0;
3420
3421
3422             this.totalFrames = Roo.lib.AnimMgr.fps;
3423
3424
3425             this.getEl = function() {
3426                 return el;
3427             };
3428
3429
3430             this.isAnimated = function() {
3431                 return isAnimated;
3432             };
3433
3434
3435             this.getStartTime = function() {
3436                 return startTime;
3437             };
3438
3439             this.runtimeAttributes = {};
3440
3441
3442             this.animate = function() {
3443                 if (this.isAnimated()) {
3444                     return false;
3445                 }
3446
3447                 this.currentFrame = 0;
3448
3449                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3450
3451                 Roo.lib.AnimMgr.registerElement(this);
3452             };
3453
3454
3455             this.stop = function(finish) {
3456                 if (finish) {
3457                     this.currentFrame = this.totalFrames;
3458                     this._onTween.fire();
3459                 }
3460                 Roo.lib.AnimMgr.stop(this);
3461             };
3462
3463             var onStart = function() {
3464                 this.onStart.fire();
3465
3466                 this.runtimeAttributes = {};
3467                 for (var attr in this.attributes) {
3468                     this.setRuntimeAttribute(attr);
3469                 }
3470
3471                 isAnimated = true;
3472                 actualFrames = 0;
3473                 startTime = new Date();
3474             };
3475
3476
3477             var onTween = function() {
3478                 var data = {
3479                     duration: new Date() - this.getStartTime(),
3480                     currentFrame: this.currentFrame
3481                 };
3482
3483                 data.toString = function() {
3484                     return (
3485                             'duration: ' + data.duration +
3486                             ', currentFrame: ' + data.currentFrame
3487                             );
3488                 };
3489
3490                 this.onTween.fire(data);
3491
3492                 var runtimeAttributes = this.runtimeAttributes;
3493
3494                 for (var attr in runtimeAttributes) {
3495                     this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3496                 }
3497
3498                 actualFrames += 1;
3499             };
3500
3501             var onComplete = function() {
3502                 var actual_duration = (new Date() - startTime) / 1000 ;
3503
3504                 var data = {
3505                     duration: actual_duration,
3506                     frames: actualFrames,
3507                     fps: actualFrames / actual_duration
3508                 };
3509
3510                 data.toString = function() {
3511                     return (
3512                             'duration: ' + data.duration +
3513                             ', frames: ' + data.frames +
3514                             ', fps: ' + data.fps
3515                             );
3516                 };
3517
3518                 isAnimated = false;
3519                 actualFrames = 0;
3520                 this.onComplete.fire(data);
3521             };
3522
3523
3524             this._onStart = new Roo.util.Event(this);
3525             this.onStart = new Roo.util.Event(this);
3526             this.onTween = new Roo.util.Event(this);
3527             this._onTween = new Roo.util.Event(this);
3528             this.onComplete = new Roo.util.Event(this);
3529             this._onComplete = new Roo.util.Event(this);
3530             this._onStart.addListener(onStart);
3531             this._onTween.addListener(onTween);
3532             this._onComplete.addListener(onComplete);
3533         }
3534     };
3535 })();
3536 /*
3537  * Portions of this file are based on pieces of Yahoo User Interface Library
3538  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3539  * YUI licensed under the BSD License:
3540  * http://developer.yahoo.net/yui/license.txt
3541  * <script type="text/javascript">
3542  *
3543  */
3544
3545 Roo.lib.AnimMgr = new function() {
3546
3547     var thread = null;
3548
3549
3550     var queue = [];
3551
3552
3553     var tweenCount = 0;
3554
3555
3556     this.fps = 1000;
3557
3558
3559     this.delay = 1;
3560
3561
3562     this.registerElement = function(tween) {
3563         queue[queue.length] = tween;
3564         tweenCount += 1;
3565         tween._onStart.fire();
3566         this.start();
3567     };
3568
3569
3570     this.unRegister = function(tween, index) {
3571         tween._onComplete.fire();
3572         index = index || getIndex(tween);
3573         if (index != -1) {
3574             queue.splice(index, 1);
3575         }
3576
3577         tweenCount -= 1;
3578         if (tweenCount <= 0) {
3579             this.stop();
3580         }
3581     };
3582
3583
3584     this.start = function() {
3585         if (thread === null) {
3586             thread = setInterval(this.run, this.delay);
3587         }
3588     };
3589
3590
3591     this.stop = function(tween) {
3592         if (!tween) {
3593             clearInterval(thread);
3594
3595             for (var i = 0, len = queue.length; i < len; ++i) {
3596                 if (queue[0].isAnimated()) {
3597                     this.unRegister(queue[0], 0);
3598                 }
3599             }
3600
3601             queue = [];
3602             thread = null;
3603             tweenCount = 0;
3604         }
3605         else {
3606             this.unRegister(tween);
3607         }
3608     };
3609
3610
3611     this.run = function() {
3612         for (var i = 0, len = queue.length; i < len; ++i) {
3613             var tween = queue[i];
3614             if (!tween || !tween.isAnimated()) {
3615                 continue;
3616             }
3617
3618             if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3619             {
3620                 tween.currentFrame += 1;
3621
3622                 if (tween.useSeconds) {
3623                     correctFrame(tween);
3624                 }
3625                 tween._onTween.fire();
3626             }
3627             else {
3628                 Roo.lib.AnimMgr.stop(tween, i);
3629             }
3630         }
3631     };
3632
3633     var getIndex = function(anim) {
3634         for (var i = 0, len = queue.length; i < len; ++i) {
3635             if (queue[i] == anim) {
3636                 return i;
3637             }
3638         }
3639         return -1;
3640     };
3641
3642
3643     var correctFrame = function(tween) {
3644         var frames = tween.totalFrames;
3645         var frame = tween.currentFrame;
3646         var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3647         var elapsed = (new Date() - tween.getStartTime());
3648         var tweak = 0;
3649
3650         if (elapsed < tween.duration * 1000) {
3651             tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3652         } else {
3653             tweak = frames - (frame + 1);
3654         }
3655         if (tweak > 0 && isFinite(tweak)) {
3656             if (tween.currentFrame + tweak >= frames) {
3657                 tweak = frames - (frame + 1);
3658             }
3659
3660             tween.currentFrame += tweak;
3661         }
3662     };
3663 };
3664
3665     /*
3666  * Portions of this file are based on pieces of Yahoo User Interface Library
3667  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3668  * YUI licensed under the BSD License:
3669  * http://developer.yahoo.net/yui/license.txt
3670  * <script type="text/javascript">
3671  *
3672  */
3673 Roo.lib.Bezier = new function() {
3674
3675         this.getPosition = function(points, t) {
3676             var n = points.length;
3677             var tmp = [];
3678
3679             for (var i = 0; i < n; ++i) {
3680                 tmp[i] = [points[i][0], points[i][1]];
3681             }
3682
3683             for (var j = 1; j < n; ++j) {
3684                 for (i = 0; i < n - j; ++i) {
3685                     tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3686                     tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3687                 }
3688             }
3689
3690             return [ tmp[0][0], tmp[0][1] ];
3691
3692         };
3693     }; 
3694
3695 /**
3696  * @class Roo.lib.Color
3697  * @constructor
3698  * An abstract Color implementation. Concrete Color implementations should use
3699  * an instance of this function as their prototype, and implement the getRGB and
3700  * getHSL functions. getRGB should return an object representing the RGB
3701  * components of this Color, with the red, green, and blue components in the
3702  * range [0,255] and the alpha component in the range [0,100]. getHSL should
3703  * return an object representing the HSL components of this Color, with the hue
3704  * component in the range [0,360), the saturation and lightness components in
3705  * the range [0,100], and the alpha component in the range [0,1].
3706  *
3707  *
3708  * Color.js
3709  *
3710  * Functions for Color handling and processing.
3711  *
3712  * http://www.safalra.com/web-design/javascript/Color-handling-and-processing/
3713  *
3714  * The author of this program, Safalra (Stephen Morley), irrevocably releases all
3715  * rights to this program, with the intention of it becoming part of the public
3716  * domain. Because this program is released into the public domain, it comes with
3717  * no warranty either expressed or implied, to the extent permitted by law.
3718  * 
3719  * For more free and public domain JavaScript code by the same author, visit:
3720  * http://www.safalra.com/web-design/javascript/
3721  * 
3722  */
3723 Roo.lib.Color = function() { }
3724
3725
3726 Roo.apply(Roo.lib.Color.prototype, {
3727   
3728   rgb : null,
3729   hsv : null,
3730   hsl : null,
3731   
3732   /**
3733    * getIntegerRGB
3734    * @return {Object} an object representing the RGBA components of this Color. The red,
3735    * green, and blue components are converted to integers in the range [0,255].
3736    * The alpha is a value in the range [0,1].
3737    */
3738   getIntegerRGB : function(){
3739
3740     // get the RGB components of this Color
3741     var rgb = this.getRGB();
3742
3743     // return the integer components
3744     return {
3745       'r' : Math.round(rgb.r),
3746       'g' : Math.round(rgb.g),
3747       'b' : Math.round(rgb.b),
3748       'a' : rgb.a
3749     };
3750
3751   },
3752
3753   /**
3754    * getPercentageRGB
3755    * @return {Object} an object representing the RGBA components of this Color. The red,
3756    * green, and blue components are converted to numbers in the range [0,100].
3757    * The alpha is a value in the range [0,1].
3758    */
3759   getPercentageRGB : function(){
3760
3761     // get the RGB components of this Color
3762     var rgb = this.getRGB();
3763
3764     // return the percentage components
3765     return {
3766       'r' : 100 * rgb.r / 255,
3767       'g' : 100 * rgb.g / 255,
3768       'b' : 100 * rgb.b / 255,
3769       'a' : rgb.a
3770     };
3771
3772   },
3773
3774   /**
3775    * getCSSHexadecimalRGB
3776    * @return {String} a string representing this Color as a CSS hexadecimal RGB Color
3777    * value - that is, a string of the form #RRGGBB where each of RR, GG, and BB
3778    * are two-digit hexadecimal numbers.
3779    */
3780   getCSSHexadecimalRGB : function()
3781   {
3782
3783     // get the integer RGB components
3784     var rgb = this.getIntegerRGB();
3785
3786     // determine the hexadecimal equivalents
3787     var r16 = rgb.r.toString(16);
3788     var g16 = rgb.g.toString(16);
3789     var b16 = rgb.b.toString(16);
3790
3791     // return the CSS RGB Color value
3792     return '#'
3793         + (r16.length == 2 ? r16 : '0' + r16)
3794         + (g16.length == 2 ? g16 : '0' + g16)
3795         + (b16.length == 2 ? b16 : '0' + b16);
3796
3797   },
3798
3799   /**
3800    * getCSSIntegerRGB
3801    * @return {String} a string representing this Color as a CSS integer RGB Color
3802    * value - that is, a string of the form rgb(r,g,b) where each of r, g, and b
3803    * are integers in the range [0,255].
3804    */
3805   getCSSIntegerRGB : function(){
3806
3807     // get the integer RGB components
3808     var rgb = this.getIntegerRGB();
3809
3810     // return the CSS RGB Color value
3811     return 'rgb(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ')';
3812
3813   },
3814
3815   /**
3816    * getCSSIntegerRGBA
3817    * @return {String} Returns a string representing this Color as a CSS integer RGBA Color
3818    * value - that is, a string of the form rgba(r,g,b,a) where each of r, g, and
3819    * b are integers in the range [0,255] and a is in the range [0,1].
3820    */
3821   getCSSIntegerRGBA : function(){
3822
3823     // get the integer RGB components
3824     var rgb = this.getIntegerRGB();
3825
3826     // return the CSS integer RGBA Color value
3827     return 'rgb(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ',' + rgb.a + ')';
3828
3829   },
3830
3831   /**
3832    * getCSSPercentageRGB
3833    * @return {String} a string representing this Color as a CSS percentage RGB Color
3834    * value - that is, a string of the form rgb(r%,g%,b%) where each of r, g, and
3835    * b are in the range [0,100].
3836    */
3837   getCSSPercentageRGB : function(){
3838
3839     // get the percentage RGB components
3840     var rgb = this.getPercentageRGB();
3841
3842     // return the CSS RGB Color value
3843     return 'rgb(' + rgb.r + '%,' + rgb.g + '%,' + rgb.b + '%)';
3844
3845   },
3846
3847   /**
3848    * getCSSPercentageRGBA
3849    * @return {String} a string representing this Color as a CSS percentage RGBA Color
3850    * value - that is, a string of the form rgba(r%,g%,b%,a) where each of r, g,
3851    * and b are in the range [0,100] and a is in the range [0,1].
3852    */
3853   getCSSPercentageRGBA : function(){
3854
3855     // get the percentage RGB components
3856     var rgb = this.getPercentageRGB();
3857
3858     // return the CSS percentage RGBA Color value
3859     return 'rgb(' + rgb.r + '%,' + rgb.g + '%,' + rgb.b + '%,' + rgb.a + ')';
3860
3861   },
3862
3863   /**
3864    * getCSSHSL
3865    * @return {String} a string representing this Color as a CSS HSL Color value - that
3866    * is, a string of the form hsl(h,s%,l%) where h is in the range [0,100] and
3867    * s and l are in the range [0,100].
3868    */
3869   getCSSHSL : function(){
3870
3871     // get the HSL components
3872     var hsl = this.getHSL();
3873
3874     // return the CSS HSL Color value
3875     return 'hsl(' + hsl.h + ',' + hsl.s + '%,' + hsl.l + '%)';
3876
3877   },
3878
3879   /**
3880    * getCSSHSLA
3881    * @return {String} a string representing this Color as a CSS HSLA Color value - that
3882    * is, a string of the form hsla(h,s%,l%,a) where h is in the range [0,100],
3883    * s and l are in the range [0,100], and a is in the range [0,1].
3884    */
3885   getCSSHSLA : function(){
3886
3887     // get the HSL components
3888     var hsl = this.getHSL();
3889
3890     // return the CSS HSL Color value
3891     return 'hsl(' + hsl.h + ',' + hsl.s + '%,' + hsl.l + '%,' + hsl.a + ')';
3892
3893   },
3894
3895   /**
3896    * Sets the Color of the specified node to this Color. This functions sets
3897    * the CSS 'color' property for the node. The parameter is:
3898    * 
3899    * @param {DomElement} node - the node whose Color should be set
3900    */
3901   setNodeColor : function(node){
3902
3903     // set the Color of the node
3904     node.style.color = this.getCSSHexadecimalRGB();
3905
3906   },
3907
3908   /**
3909    * Sets the background Color of the specified node to this Color. This
3910    * functions sets the CSS 'background-color' property for the node. The
3911    * parameter is:
3912    *
3913    * @param {DomElement} node - the node whose background Color should be set
3914    */
3915   setNodeBackgroundColor : function(node){
3916
3917     // set the background Color of the node
3918     node.style.backgroundColor = this.getCSSHexadecimalRGB();
3919
3920   },
3921   // convert between formats..
3922   toRGB: function()
3923   {
3924     var r = this.getIntegerRGB();
3925     return new Roo.lib.RGBColor(r.r,r.g,r.b,r.a);
3926     
3927   },
3928   toHSL : function()
3929   {
3930      var hsl = this.getHSL();
3931   // return the CSS HSL Color value
3932     return new Roo.lib.HSLColor(hsl.h,  hsl.s, hsl.l ,  hsl.a );
3933     
3934   },
3935   
3936   toHSV : function()
3937   {
3938     var rgb = this.toRGB();
3939     var hsv = rgb.getHSV();
3940    // return the CSS HSL Color value
3941     return new Roo.lib.HSVColor(hsv.h,  hsv.s, hsv.v ,  hsv.a );
3942     
3943   },
3944   
3945   // modify  v = 0 ... 1 (eg. 0.5)
3946   saturate : function(v)
3947   {
3948       var rgb = this.toRGB();
3949       var hsv = rgb.getHSV();
3950       return new Roo.lib.HSVColor(hsv.h,  hsv.s * v, hsv.v ,  hsv.a );
3951       
3952   
3953   },
3954   
3955    
3956   /**
3957    * getRGB
3958    * @return {Object} the RGB and alpha components of this Color as an object with r,
3959    * g, b, and a properties. r, g, and b are in the range [0,255] and a is in
3960    * the range [0,1].
3961    */
3962   getRGB: function(){
3963    
3964     // return the RGB components
3965     return {
3966       'r' : this.rgb.r,
3967       'g' : this.rgb.g,
3968       'b' : this.rgb.b,
3969       'a' : this.alpha
3970     };
3971
3972   },
3973
3974   /**
3975    * getHSV
3976    * @return {Object} the HSV and alpha components of this Color as an object with h,
3977    * s, v, and a properties. h is in the range [0,360), s and v are in the range
3978    * [0,100], and a is in the range [0,1].
3979    */
3980   getHSV : function()
3981   {
3982     
3983     // calculate the HSV components if necessary
3984     if (this.hsv == null) {
3985       this.calculateHSV();
3986     }
3987
3988     // return the HSV components
3989     return {
3990       'h' : this.hsv.h,
3991       's' : this.hsv.s,
3992       'v' : this.hsv.v,
3993       'a' : this.alpha
3994     };
3995
3996   },
3997
3998   /**
3999    * getHSL
4000    * @return {Object} the HSL and alpha components of this Color as an object with h,
4001    * s, l, and a properties. h is in the range [0,360), s and l are in the range
4002    * [0,100], and a is in the range [0,1].
4003    */
4004   getHSL : function(){
4005     
4006      
4007     // calculate the HSV components if necessary
4008     if (this.hsl == null) { this.calculateHSL(); }
4009
4010     // return the HSL components
4011     return {
4012       'h' : this.hsl.h,
4013       's' : this.hsl.s,
4014       'l' : this.hsl.l,
4015       'a' : this.alpha
4016     };
4017
4018   }
4019   
4020
4021 });
4022
4023
4024 /**
4025  * @class Roo.lib.RGBColor
4026  * @extends Roo.lib.Color
4027  * Creates a Color specified in the RGB Color space, with an optional alpha
4028  * component. The parameters are:
4029  * @constructor
4030  * 
4031
4032  * @param {Number} r - the red component, clipped to the range [0,255]
4033  * @param {Number} g - the green component, clipped to the range [0,255]
4034  * @param {Number} b - the blue component, clipped to the range [0,255]
4035  * @param {Number} a - the alpha component, clipped to the range [0,1] - this parameter is
4036  *     optional and defaults to 1
4037  */
4038 Roo.lib.RGBColor = function (r, g, b, a){
4039
4040   // store the alpha component after clipping it if necessary
4041   this.alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
4042
4043   // store the RGB components after clipping them if necessary
4044   this.rgb =
4045       {
4046         'r' : Math.max(0, Math.min(255, r)),
4047         'g' : Math.max(0, Math.min(255, g)),
4048         'b' : Math.max(0, Math.min(255, b))
4049       };
4050
4051   // initialise the HSV and HSL components to null
4052   
4053
4054   /* 
4055    * //private returns the HSV or HSL hue component of this RGBColor. The hue is in the
4056    * range [0,360). The parameters are:
4057    *
4058    * maximum - the maximum of the RGB component values
4059    * range   - the range of the RGB component values
4060    */
4061    
4062
4063 }
4064 // this does an 'exteds'
4065 Roo.extend(Roo.lib.RGBColor, Roo.lib.Color, {
4066
4067   
4068     getHue  : function(maximum, range)
4069     {
4070       var rgb = this.rgb;
4071        
4072       // check whether the range is zero
4073       if (range == 0){
4074   
4075         // set the hue to zero (any hue is acceptable as the Color is grey)
4076         var hue = 0;
4077   
4078       }else{
4079   
4080         // determine which of the components has the highest value and set the hue
4081         switch (maximum){
4082   
4083           // red has the highest value
4084           case rgb.r:
4085             var hue = (rgb.g - rgb.b) / range * 60;
4086             if (hue < 0) { hue += 360; }
4087             break;
4088   
4089           // green has the highest value
4090           case rgb.g:
4091             var hue = (rgb.b - rgb.r) / range * 60 + 120;
4092             break;
4093   
4094           // blue has the highest value
4095           case rgb.b:
4096             var hue = (rgb.r - rgb.g) / range * 60 + 240;
4097             break;
4098   
4099         }
4100   
4101       }
4102   
4103       // return the hue
4104       return hue;
4105   
4106     },
4107
4108   /* //private Calculates and stores the HSV components of this RGBColor so that they can
4109    * be returned be the getHSV function.
4110    */
4111    calculateHSV : function(){
4112     var rgb = this.rgb;
4113     // get the maximum and range of the RGB component values
4114     var maximum = Math.max(rgb.r, rgb.g, rgb.b);
4115     var range   = maximum - Math.min(rgb.r, rgb.g, rgb.b);
4116
4117     // store the HSV components
4118     this.hsv =
4119         {
4120           'h' : this.getHue(maximum, range),
4121           's' : (maximum == 0 ? 0 : 100 * range / maximum),
4122           'v' : maximum / 2.55
4123         };
4124
4125   },
4126
4127   /* //private Calculates and stores the HSL components of this RGBColor so that they can
4128    * be returned be the getHSL function.
4129    */
4130    calculateHSL : function(){
4131     var rgb = this.rgb;
4132     // get the maximum and range of the RGB component values
4133     var maximum = Math.max(rgb.r, rgb.g, rgb.b);
4134     var range   = maximum - Math.min(rgb.r, rgb.g, rgb.b);
4135
4136     // determine the lightness in the range [0,1]
4137     var l = maximum / 255 - range / 510;
4138
4139     // store the HSL components
4140     this.hsl =
4141         {
4142           'h' : this.getHue(maximum, range),
4143           's' : (range == 0 ? 0 : range / 2.55 / (l < 0.5 ? l * 2 : 2 - l * 2)),
4144           'l' : 100 * l
4145         };
4146
4147   }
4148
4149 });
4150
4151 /**
4152  * @class Roo.lib.HSVColor
4153  * @extends Roo.lib.Color
4154  * Creates a Color specified in the HSV Color space, with an optional alpha
4155  * component. The parameters are:
4156  * @constructor
4157  *
4158  * @param {Number} h - the hue component, wrapped to the range [0,360)
4159  * @param {Number} s - the saturation component, clipped to the range [0,100]
4160  * @param {Number} v - the value component, clipped to the range [0,100]
4161  * @param {Number} a - the alpha component, clipped to the range [0,1] - this parameter is
4162  *     optional and defaults to 1
4163  */
4164 Roo.lib.HSVColor = function (h, s, v, a){
4165
4166   // store the alpha component after clipping it if necessary
4167   this.alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
4168
4169   // store the HSV components after clipping or wrapping them if necessary
4170   this.hsv =
4171       {
4172         'h' : (h % 360 + 360) % 360,
4173         's' : Math.max(0, Math.min(100, s)),
4174         'v' : Math.max(0, Math.min(100, v))
4175       };
4176
4177   // initialise the RGB and HSL components to null
4178   this.rgb = null;
4179   this.hsl = null;
4180 }
4181
4182 Roo.extend(Roo.lib.HSVColor, Roo.lib.Color, {
4183   /* Calculates and stores the RGB components of this HSVColor so that they can
4184    * be returned be the getRGB function.
4185    */
4186   calculateRGB: function ()
4187   {
4188     var hsv = this.hsv;
4189     // check whether the saturation is zero
4190     if (hsv.s == 0){
4191
4192       // set the Color to the appropriate shade of grey
4193       var r = hsv.v;
4194       var g = hsv.v;
4195       var b = hsv.v;
4196
4197     }else{
4198
4199       // set some temporary values
4200       var f  = hsv.h / 60 - Math.floor(hsv.h / 60);
4201       var p  = hsv.v * (1 - hsv.s / 100);
4202       var q  = hsv.v * (1 - hsv.s / 100 * f);
4203       var t  = hsv.v * (1 - hsv.s / 100 * (1 - f));
4204
4205       // set the RGB Color components to their temporary values
4206       switch (Math.floor(hsv.h / 60)){
4207         case 0: var r = hsv.v; var g = t; var b = p; break;
4208         case 1: var r = q; var g = hsv.v; var b = p; break;
4209         case 2: var r = p; var g = hsv.v; var b = t; break;
4210         case 3: var r = p; var g = q; var b = hsv.v; break;
4211         case 4: var r = t; var g = p; var b = hsv.v; break;
4212         case 5: var r = hsv.v; var g = p; var b = q; break;
4213       }
4214
4215     }
4216
4217     // store the RGB components
4218     this.rgb =
4219         {
4220           'r' : r * 2.55,
4221           'g' : g * 2.55,
4222           'b' : b * 2.55
4223         };
4224
4225   },
4226
4227   /* Calculates and stores the HSL components of this HSVColor so that they can
4228    * be returned be the getHSL function.
4229    */
4230   calculateHSL : function (){
4231
4232     var hsv = this.hsv;
4233     // determine the lightness in the range [0,100]
4234     var l = (2 - hsv.s / 100) * hsv.v / 2;
4235
4236     // store the HSL components
4237     this.hsl =
4238         {
4239           'h' : hsv.h,
4240           's' : hsv.s * hsv.v / (l < 50 ? l * 2 : 200 - l * 2),
4241           'l' : l
4242         };
4243
4244     // correct a division-by-zero error
4245     if (isNaN(hsl.s)) { hsl.s = 0; }
4246
4247   } 
4248  
4249
4250 });
4251  
4252
4253 /**
4254  * @class Roo.lib.HSLColor
4255  * @extends Roo.lib.Color
4256  *
4257  * @constructor
4258  * Creates a Color specified in the HSL Color space, with an optional alpha
4259  * component. The parameters are:
4260  *
4261  * @param {Number} h - the hue component, wrapped to the range [0,360)
4262  * @param {Number} s - the saturation component, clipped to the range [0,100]
4263  * @param {Number} l - the lightness component, clipped to the range [0,100]
4264  * @param {Number} a - the alpha component, clipped to the range [0,1] - this parameter is
4265  *     optional and defaults to 1
4266  */
4267
4268 Roo.lib.HSLColor = function(h, s, l, a){
4269
4270   // store the alpha component after clipping it if necessary
4271   this.alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
4272
4273   // store the HSL components after clipping or wrapping them if necessary
4274   this.hsl =
4275       {
4276         'h' : (h % 360 + 360) % 360,
4277         's' : Math.max(0, Math.min(100, s)),
4278         'l' : Math.max(0, Math.min(100, l))
4279       };
4280
4281   // initialise the RGB and HSV components to null
4282 }
4283
4284 Roo.extend(Roo.lib.HSLColor, Roo.lib.Color, {
4285
4286   /* Calculates and stores the RGB components of this HSLColor so that they can
4287    * be returned be the getRGB function.
4288    */
4289   calculateRGB: function (){
4290
4291     // check whether the saturation is zero
4292     if (this.hsl.s == 0){
4293
4294       // store the RGB components representing the appropriate shade of grey
4295       this.rgb =
4296           {
4297             'r' : this.hsl.l * 2.55,
4298             'g' : this.hsl.l * 2.55,
4299             'b' : this.hsl.l * 2.55
4300           };
4301
4302     }else{
4303
4304       // set some temporary values
4305       var p = this.hsl.l < 50
4306             ? this.hsl.l * (1 + hsl.s / 100)
4307             : this.hsl.l + hsl.s - hsl.l * hsl.s / 100;
4308       var q = 2 * hsl.l - p;
4309
4310       // initialise the RGB components
4311       this.rgb =
4312           {
4313             'r' : (h + 120) / 60 % 6,
4314             'g' : h / 60,
4315             'b' : (h + 240) / 60 % 6
4316           };
4317
4318       // loop over the RGB components
4319       for (var key in this.rgb){
4320
4321         // ensure that the property is not inherited from the root object
4322         if (this.rgb.hasOwnProperty(key)){
4323
4324           // set the component to its value in the range [0,100]
4325           if (this.rgb[key] < 1){
4326             this.rgb[key] = q + (p - q) * this.rgb[key];
4327           }else if (this.rgb[key] < 3){
4328             this.rgb[key] = p;
4329           }else if (this.rgb[key] < 4){
4330             this.rgb[key] = q + (p - q) * (4 - this.rgb[key]);
4331           }else{
4332             this.rgb[key] = q;
4333           }
4334
4335           // set the component to its value in the range [0,255]
4336           this.rgb[key] *= 2.55;
4337
4338         }
4339
4340       }
4341
4342     }
4343
4344   },
4345
4346   /* Calculates and stores the HSV components of this HSLColor so that they can
4347    * be returned be the getHSL function.
4348    */
4349    calculateHSV : function(){
4350
4351     // set a temporary value
4352     var t = this.hsl.s * (this.hsl.l < 50 ? this.hsl.l : 100 - this.hsl.l) / 100;
4353
4354     // store the HSV components
4355     this.hsv =
4356         {
4357           'h' : this.hsl.h,
4358           's' : 200 * t / (this.hsl.l + t),
4359           'v' : t + this.hsl.l
4360         };
4361
4362     // correct a division-by-zero error
4363     if (isNaN(this.hsv.s)) { this.hsv.s = 0; }
4364
4365   }
4366  
4367
4368 });
4369 /*
4370  * Portions of this file are based on pieces of Yahoo User Interface Library
4371  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4372  * YUI licensed under the BSD License:
4373  * http://developer.yahoo.net/yui/license.txt
4374  * <script type="text/javascript">
4375  *
4376  */
4377 (function() {
4378
4379     Roo.lib.ColorAnim = function(el, attributes, duration, method) {
4380         Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
4381     };
4382
4383     Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
4384
4385     var fly = Roo.lib.AnimBase.fly;
4386     var Y = Roo.lib;
4387     var superclass = Y.ColorAnim.superclass;
4388     var proto = Y.ColorAnim.prototype;
4389
4390     proto.toString = function() {
4391         var el = this.getEl();
4392         var id = el.id || el.tagName;
4393         return ("ColorAnim " + id);
4394     };
4395
4396     proto.patterns.color = /color$/i;
4397     proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
4398     proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
4399     proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
4400     proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
4401
4402
4403     proto.parseColor = function(s) {
4404         if (s.length == 3) {
4405             return s;
4406         }
4407
4408         var c = this.patterns.hex.exec(s);
4409         if (c && c.length == 4) {
4410             return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
4411         }
4412
4413         c = this.patterns.rgb.exec(s);
4414         if (c && c.length == 4) {
4415             return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
4416         }
4417
4418         c = this.patterns.hex3.exec(s);
4419         if (c && c.length == 4) {
4420             return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
4421         }
4422
4423         return null;
4424     };
4425     // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
4426     proto.getAttribute = function(attr) {
4427         var el = this.getEl();
4428         if (this.patterns.color.test(attr)) {
4429             var val = fly(el).getStyle(attr);
4430
4431             if (this.patterns.transparent.test(val)) {
4432                 var parent = el.parentNode;
4433                 val = fly(parent).getStyle(attr);
4434
4435                 while (parent && this.patterns.transparent.test(val)) {
4436                     parent = parent.parentNode;
4437                     val = fly(parent).getStyle(attr);
4438                     if (parent.tagName.toUpperCase() == 'HTML') {
4439                         val = '#fff';
4440                     }
4441                 }
4442             }
4443         } else {
4444             val = superclass.getAttribute.call(this, attr);
4445         }
4446
4447         return val;
4448     };
4449     proto.getAttribute = function(attr) {
4450         var el = this.getEl();
4451         if (this.patterns.color.test(attr)) {
4452             var val = fly(el).getStyle(attr);
4453
4454             if (this.patterns.transparent.test(val)) {
4455                 var parent = el.parentNode;
4456                 val = fly(parent).getStyle(attr);
4457
4458                 while (parent && this.patterns.transparent.test(val)) {
4459                     parent = parent.parentNode;
4460                     val = fly(parent).getStyle(attr);
4461                     if (parent.tagName.toUpperCase() == 'HTML') {
4462                         val = '#fff';
4463                     }
4464                 }
4465             }
4466         } else {
4467             val = superclass.getAttribute.call(this, attr);
4468         }
4469
4470         return val;
4471     };
4472
4473     proto.doMethod = function(attr, start, end) {
4474         var val;
4475
4476         if (this.patterns.color.test(attr)) {
4477             val = [];
4478             for (var i = 0, len = start.length; i < len; ++i) {
4479                 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
4480             }
4481
4482             val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
4483         }
4484         else {
4485             val = superclass.doMethod.call(this, attr, start, end);
4486         }
4487
4488         return val;
4489     };
4490
4491     proto.setRuntimeAttribute = function(attr) {
4492         superclass.setRuntimeAttribute.call(this, attr);
4493
4494         if (this.patterns.color.test(attr)) {
4495             var attributes = this.attributes;
4496             var start = this.parseColor(this.runtimeAttributes[attr].start);
4497             var end = this.parseColor(this.runtimeAttributes[attr].end);
4498
4499             if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
4500                 end = this.parseColor(attributes[attr].by);
4501
4502                 for (var i = 0, len = start.length; i < len; ++i) {
4503                     end[i] = start[i] + end[i];
4504                 }
4505             }
4506
4507             this.runtimeAttributes[attr].start = start;
4508             this.runtimeAttributes[attr].end = end;
4509         }
4510     };
4511 })();
4512
4513 /*
4514  * Portions of this file are based on pieces of Yahoo User Interface Library
4515  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4516  * YUI licensed under the BSD License:
4517  * http://developer.yahoo.net/yui/license.txt
4518  * <script type="text/javascript">
4519  *
4520  */
4521 Roo.lib.Easing = {
4522
4523
4524     easeNone: function (t, b, c, d) {
4525         return c * t / d + b;
4526     },
4527
4528
4529     easeIn: function (t, b, c, d) {
4530         return c * (t /= d) * t + b;
4531     },
4532
4533
4534     easeOut: function (t, b, c, d) {
4535         return -c * (t /= d) * (t - 2) + b;
4536     },
4537
4538
4539     easeBoth: function (t, b, c, d) {
4540         if ((t /= d / 2) < 1) {
4541             return c / 2 * t * t + b;
4542         }
4543
4544         return -c / 2 * ((--t) * (t - 2) - 1) + b;
4545     },
4546
4547
4548     easeInStrong: function (t, b, c, d) {
4549         return c * (t /= d) * t * t * t + b;
4550     },
4551
4552
4553     easeOutStrong: function (t, b, c, d) {
4554         return -c * ((t = t / d - 1) * t * t * t - 1) + b;
4555     },
4556
4557
4558     easeBothStrong: function (t, b, c, d) {
4559         if ((t /= d / 2) < 1) {
4560             return c / 2 * t * t * t * t + b;
4561         }
4562
4563         return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
4564     },
4565
4566
4567
4568     elasticIn: function (t, b, c, d, a, p) {
4569         if (t == 0) {
4570             return b;
4571         }
4572         if ((t /= d) == 1) {
4573             return b + c;
4574         }
4575         if (!p) {
4576             p = d * .3;
4577         }
4578
4579         if (!a || a < Math.abs(c)) {
4580             a = c;
4581             var s = p / 4;
4582         }
4583         else {
4584             var s = p / (2 * Math.PI) * Math.asin(c / a);
4585         }
4586
4587         return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
4588     },
4589
4590
4591     elasticOut: function (t, b, c, d, a, p) {
4592         if (t == 0) {
4593             return b;
4594         }
4595         if ((t /= d) == 1) {
4596             return b + c;
4597         }
4598         if (!p) {
4599             p = d * .3;
4600         }
4601
4602         if (!a || a < Math.abs(c)) {
4603             a = c;
4604             var s = p / 4;
4605         }
4606         else {
4607             var s = p / (2 * Math.PI) * Math.asin(c / a);
4608         }
4609
4610         return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
4611     },
4612
4613
4614     elasticBoth: function (t, b, c, d, a, p) {
4615         if (t == 0) {
4616             return b;
4617         }
4618
4619         if ((t /= d / 2) == 2) {
4620             return b + c;
4621         }
4622
4623         if (!p) {
4624             p = d * (.3 * 1.5);
4625         }
4626
4627         if (!a || a < Math.abs(c)) {
4628             a = c;
4629             var s = p / 4;
4630         }
4631         else {
4632             var s = p / (2 * Math.PI) * Math.asin(c / a);
4633         }
4634
4635         if (t < 1) {
4636             return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
4637                           Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
4638         }
4639         return a * Math.pow(2, -10 * (t -= 1)) *
4640                Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
4641     },
4642
4643
4644
4645     backIn: function (t, b, c, d, s) {
4646         if (typeof s == 'undefined') {
4647             s = 1.70158;
4648         }
4649         return c * (t /= d) * t * ((s + 1) * t - s) + b;
4650     },
4651
4652
4653     backOut: function (t, b, c, d, s) {
4654         if (typeof s == 'undefined') {
4655             s = 1.70158;
4656         }
4657         return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
4658     },
4659
4660
4661     backBoth: function (t, b, c, d, s) {
4662         if (typeof s == 'undefined') {
4663             s = 1.70158;
4664         }
4665
4666         if ((t /= d / 2 ) < 1) {
4667             return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
4668         }
4669         return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
4670     },
4671
4672
4673     bounceIn: function (t, b, c, d) {
4674         return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
4675     },
4676
4677
4678     bounceOut: function (t, b, c, d) {
4679         if ((t /= d) < (1 / 2.75)) {
4680             return c * (7.5625 * t * t) + b;
4681         } else if (t < (2 / 2.75)) {
4682             return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
4683         } else if (t < (2.5 / 2.75)) {
4684             return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
4685         }
4686         return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
4687     },
4688
4689
4690     bounceBoth: function (t, b, c, d) {
4691         if (t < d / 2) {
4692             return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
4693         }
4694         return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
4695     }
4696 };/*
4697  * Portions of this file are based on pieces of Yahoo User Interface Library
4698  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4699  * YUI licensed under the BSD License:
4700  * http://developer.yahoo.net/yui/license.txt
4701  * <script type="text/javascript">
4702  *
4703  */
4704     (function() {
4705         Roo.lib.Motion = function(el, attributes, duration, method) {
4706             if (el) {
4707                 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
4708             }
4709         };
4710
4711         Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
4712
4713
4714         var Y = Roo.lib;
4715         var superclass = Y.Motion.superclass;
4716         var proto = Y.Motion.prototype;
4717
4718         proto.toString = function() {
4719             var el = this.getEl();
4720             var id = el.id || el.tagName;
4721             return ("Motion " + id);
4722         };
4723
4724         proto.patterns.points = /^points$/i;
4725
4726         proto.setAttribute = function(attr, val, unit) {
4727             if (this.patterns.points.test(attr)) {
4728                 unit = unit || 'px';
4729                 superclass.setAttribute.call(this, 'left', val[0], unit);
4730                 superclass.setAttribute.call(this, 'top', val[1], unit);
4731             } else {
4732                 superclass.setAttribute.call(this, attr, val, unit);
4733             }
4734         };
4735
4736         proto.getAttribute = function(attr) {
4737             if (this.patterns.points.test(attr)) {
4738                 var val = [
4739                         superclass.getAttribute.call(this, 'left'),
4740                         superclass.getAttribute.call(this, 'top')
4741                         ];
4742             } else {
4743                 val = superclass.getAttribute.call(this, attr);
4744             }
4745
4746             return val;
4747         };
4748
4749         proto.doMethod = function(attr, start, end) {
4750             var val = null;
4751
4752             if (this.patterns.points.test(attr)) {
4753                 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
4754                 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
4755             } else {
4756                 val = superclass.doMethod.call(this, attr, start, end);
4757             }
4758             return val;
4759         };
4760
4761         proto.setRuntimeAttribute = function(attr) {
4762             if (this.patterns.points.test(attr)) {
4763                 var el = this.getEl();
4764                 var attributes = this.attributes;
4765                 var start;
4766                 var control = attributes['points']['control'] || [];
4767                 var end;
4768                 var i, len;
4769
4770                 if (control.length > 0 && !(control[0] instanceof Array)) {
4771                     control = [control];
4772                 } else {
4773                     var tmp = [];
4774                     for (i = 0,len = control.length; i < len; ++i) {
4775                         tmp[i] = control[i];
4776                     }
4777                     control = tmp;
4778                 }
4779
4780                 Roo.fly(el).position();
4781
4782                 if (isset(attributes['points']['from'])) {
4783                     Roo.lib.Dom.setXY(el, attributes['points']['from']);
4784                 }
4785                 else {
4786                     Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
4787                 }
4788
4789                 start = this.getAttribute('points');
4790
4791
4792                 if (isset(attributes['points']['to'])) {
4793                     end = translateValues.call(this, attributes['points']['to'], start);
4794
4795                     var pageXY = Roo.lib.Dom.getXY(this.getEl());
4796                     for (i = 0,len = control.length; i < len; ++i) {
4797                         control[i] = translateValues.call(this, control[i], start);
4798                     }
4799
4800
4801                 } else if (isset(attributes['points']['by'])) {
4802                     end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4803
4804                     for (i = 0,len = control.length; i < len; ++i) {
4805                         control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4806                     }
4807                 }
4808
4809                 this.runtimeAttributes[attr] = [start];
4810
4811                 if (control.length > 0) {
4812                     this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4813                 }
4814
4815                 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4816             }
4817             else {
4818                 superclass.setRuntimeAttribute.call(this, attr);
4819             }
4820         };
4821
4822         var translateValues = function(val, start) {
4823             var pageXY = Roo.lib.Dom.getXY(this.getEl());
4824             val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4825
4826             return val;
4827         };
4828
4829         var isset = function(prop) {
4830             return (typeof prop !== 'undefined');
4831         };
4832     })();
4833 /*
4834  * Portions of this file are based on pieces of Yahoo User Interface Library
4835  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4836  * YUI licensed under the BSD License:
4837  * http://developer.yahoo.net/yui/license.txt
4838  * <script type="text/javascript">
4839  *
4840  */
4841     (function() {
4842         Roo.lib.Scroll = function(el, attributes, duration, method) {
4843             if (el) {
4844                 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4845             }
4846         };
4847
4848         Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4849
4850
4851         var Y = Roo.lib;
4852         var superclass = Y.Scroll.superclass;
4853         var proto = Y.Scroll.prototype;
4854
4855         proto.toString = function() {
4856             var el = this.getEl();
4857             var id = el.id || el.tagName;
4858             return ("Scroll " + id);
4859         };
4860
4861         proto.doMethod = function(attr, start, end) {
4862             var val = null;
4863
4864             if (attr == 'scroll') {
4865                 val = [
4866                         this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4867                         this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4868                         ];
4869
4870             } else {
4871                 val = superclass.doMethod.call(this, attr, start, end);
4872             }
4873             return val;
4874         };
4875
4876         proto.getAttribute = function(attr) {
4877             var val = null;
4878             var el = this.getEl();
4879
4880             if (attr == 'scroll') {
4881                 val = [ el.scrollLeft, el.scrollTop ];
4882             } else {
4883                 val = superclass.getAttribute.call(this, attr);
4884             }
4885
4886             return val;
4887         };
4888
4889         proto.setAttribute = function(attr, val, unit) {
4890             var el = this.getEl();
4891
4892             if (attr == 'scroll') {
4893                 el.scrollLeft = val[0];
4894                 el.scrollTop = val[1];
4895             } else {
4896                 superclass.setAttribute.call(this, attr, val, unit);
4897             }
4898         };
4899     })();
4900 /*
4901  * Based on:
4902  * Ext JS Library 1.1.1
4903  * Copyright(c) 2006-2007, Ext JS, LLC.
4904  *
4905  * Originally Released Under LGPL - original licence link has changed is not relivant.
4906  *
4907  * Fork - LGPL
4908  * <script type="text/javascript">
4909  */
4910
4911
4912 // nasty IE9 hack - what a pile of crap that is..
4913
4914  if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4915     Range.prototype.createContextualFragment = function (html) {
4916         var doc = window.document;
4917         var container = doc.createElement("div");
4918         container.innerHTML = html;
4919         var frag = doc.createDocumentFragment(), n;
4920         while ((n = container.firstChild)) {
4921             frag.appendChild(n);
4922         }
4923         return frag;
4924     };
4925 }
4926
4927 /**
4928  * @class Roo.DomHelper
4929  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4930  * 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>.
4931  * @static
4932  */
4933 Roo.DomHelper = function(){
4934     var tempTableEl = null;
4935     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4936     var tableRe = /^table|tbody|tr|td$/i;
4937     var xmlns = {};
4938     // build as innerHTML where available
4939     /** @ignore */
4940     var createHtml = function(o){
4941         if(typeof o == 'string'){
4942             return o;
4943         }
4944         var b = "";
4945         if(!o.tag){
4946             o.tag = "div";
4947         }
4948         b += "<" + o.tag;
4949         for(var attr in o){
4950             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") { continue; }
4951             if(attr == "style"){
4952                 var s = o["style"];
4953                 if(typeof s == "function"){
4954                     s = s.call();
4955                 }
4956                 if(typeof s == "string"){
4957                     b += ' style="' + s + '"';
4958                 }else if(typeof s == "object"){
4959                     b += ' style="';
4960                     for(var key in s){
4961                         if(typeof s[key] != "function"){
4962                             b += key + ":" + s[key] + ";";
4963                         }
4964                     }
4965                     b += '"';
4966                 }
4967             }else{
4968                 if(attr == "cls"){
4969                     b += ' class="' + o["cls"] + '"';
4970                 }else if(attr == "htmlFor"){
4971                     b += ' for="' + o["htmlFor"] + '"';
4972                 }else{
4973                     b += " " + attr + '="' + o[attr] + '"';
4974                 }
4975             }
4976         }
4977         if(emptyTags.test(o.tag)){
4978             b += "/>";
4979         }else{
4980             b += ">";
4981             var cn = o.children || o.cn;
4982             if(cn){
4983                 //http://bugs.kde.org/show_bug.cgi?id=71506
4984                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4985                     for(var i = 0, len = cn.length; i < len; i++) {
4986                         b += createHtml(cn[i], b);
4987                     }
4988                 }else{
4989                     b += createHtml(cn, b);
4990                 }
4991             }
4992             if(o.html){
4993                 b += o.html;
4994             }
4995             b += "</" + o.tag + ">";
4996         }
4997         return b;
4998     };
4999
5000     // build as dom
5001     /** @ignore */
5002     var createDom = function(o, parentNode){
5003          
5004         // defininition craeted..
5005         var ns = false;
5006         if (o.ns && o.ns != 'html') {
5007                
5008             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
5009                 xmlns[o.ns] = o.xmlns;
5010                 ns = o.xmlns;
5011             }
5012             if (typeof(xmlns[o.ns]) == 'undefined') {
5013                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
5014             }
5015             ns = xmlns[o.ns];
5016         }
5017         
5018         
5019         if (typeof(o) == 'string') {
5020             return parentNode.appendChild(document.createTextNode(o));
5021         }
5022         o.tag = o.tag || div;
5023         if (o.ns && Roo.isIE) {
5024             ns = false;
5025             o.tag = o.ns + ':' + o.tag;
5026             
5027         }
5028         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
5029         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
5030         for(var attr in o){
5031             
5032             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
5033                     attr == "style" || typeof o[attr] == "function") { continue; }
5034                     
5035             if(attr=="cls" && Roo.isIE){
5036                 el.className = o["cls"];
5037             }else{
5038                 if(useSet) { el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);}
5039                 else { 
5040                     el[attr] = o[attr];
5041                 }
5042             }
5043         }
5044         Roo.DomHelper.applyStyles(el, o.style);
5045         var cn = o.children || o.cn;
5046         if(cn){
5047             //http://bugs.kde.org/show_bug.cgi?id=71506
5048              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
5049                 for(var i = 0, len = cn.length; i < len; i++) {
5050                     createDom(cn[i], el);
5051                 }
5052             }else{
5053                 createDom(cn, el);
5054             }
5055         }
5056         if(o.html){
5057             el.innerHTML = o.html;
5058         }
5059         if(parentNode){
5060            parentNode.appendChild(el);
5061         }
5062         return el;
5063     };
5064
5065     var ieTable = function(depth, s, h, e){
5066         tempTableEl.innerHTML = [s, h, e].join('');
5067         var i = -1, el = tempTableEl;
5068         while(++i < depth && el.firstChild){
5069             el = el.firstChild;
5070         }
5071         return el;
5072     };
5073
5074     // kill repeat to save bytes
5075     var ts = '<table>',
5076         te = '</table>',
5077         tbs = ts+'<tbody>',
5078         tbe = '</tbody>'+te,
5079         trs = tbs + '<tr>',
5080         tre = '</tr>'+tbe;
5081
5082     /**
5083      * @ignore
5084      * Nasty code for IE's broken table implementation
5085      */
5086     var insertIntoTable = function(tag, where, el, html){
5087         if(!tempTableEl){
5088             tempTableEl = document.createElement('div');
5089         }
5090         var node;
5091         var before = null;
5092         if(tag == 'td'){
5093             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
5094                 return;
5095             }
5096             if(where == 'beforebegin'){
5097                 before = el;
5098                 el = el.parentNode;
5099             } else{
5100                 before = el.nextSibling;
5101                 el = el.parentNode;
5102             }
5103             node = ieTable(4, trs, html, tre);
5104         }
5105         else if(tag == 'tr'){
5106             if(where == 'beforebegin'){
5107                 before = el;
5108                 el = el.parentNode;
5109                 node = ieTable(3, tbs, html, tbe);
5110             } else if(where == 'afterend'){
5111                 before = el.nextSibling;
5112                 el = el.parentNode;
5113                 node = ieTable(3, tbs, html, tbe);
5114             } else{ // INTO a TR
5115                 if(where == 'afterbegin'){
5116                     before = el.firstChild;
5117                 }
5118                 node = ieTable(4, trs, html, tre);
5119             }
5120         } else if(tag == 'tbody'){
5121             if(where == 'beforebegin'){
5122                 before = el;
5123                 el = el.parentNode;
5124                 node = ieTable(2, ts, html, te);
5125             } else if(where == 'afterend'){
5126                 before = el.nextSibling;
5127                 el = el.parentNode;
5128                 node = ieTable(2, ts, html, te);
5129             } else{
5130                 if(where == 'afterbegin'){
5131                     before = el.firstChild;
5132                 }
5133                 node = ieTable(3, tbs, html, tbe);
5134             }
5135         } else{ // TABLE
5136             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
5137                 return;
5138             }
5139             if(where == 'afterbegin'){
5140                 before = el.firstChild;
5141             }
5142             node = ieTable(2, ts, html, te);
5143         }
5144         el.insertBefore(node, before);
5145         return node;
5146     };
5147     
5148     // this is a bit like the react update code...
5149     // 
5150     
5151     var updateNode = function(from, to)
5152     {
5153         // should we handle non-standard elements?
5154         
5155         if (from.nodeType != to.nodeType) {
5156             from.parentNode.replaceChild(to, from);
5157         }
5158         
5159         if (from.nodeType == 3) {
5160             // assume it's text?!
5161             if (from.data == to.data) {
5162                 return;
5163             }
5164             from.data = to.data;
5165             return;
5166         }
5167         
5168         // assume 'to' doesnt have '1/3 nodetypes!
5169         if (from.nodeType !=1 || from.tagName != to.tagName) {
5170             from.parentNode.replaceChild(to, from);
5171             return;
5172         }
5173         // compare attributes
5174         var ar = Array.from(from.attributes);
5175         for(var i = 0; i< ar.length;i++) {
5176             if (to.hasAttribute(ar[i].name)) {
5177                 continue;
5178             }
5179             from.removeAttribute(ar[i].name);
5180         }
5181         ar = to.attributes;
5182         for(var i = 0; i< ar.length;i++) {
5183             if (from.getAttribute(ar[i].name) == to.getAttribute(ar[i].name)) {
5184                 continue;
5185             }
5186             from.setAttribute(ar[i].name, to.getAttribute(ar[i].name));
5187         }
5188         // children
5189         var far = Array.from(from.childNodes);
5190         var tar = Array.from(to.childNodes);
5191         // if the lengths are different.. then it's probably a editable content change, rather than
5192         // a change of the block definition..
5193         if (from.innerHTML == to.innerHTML) {
5194             return;
5195         }
5196         if (far.length != tar.length) {
5197             from.innerHTML = to.innerHTML;
5198             return;
5199         }
5200         
5201         for(var i = 0; i < far.length; i++) {
5202             updateNode(far[i], tar[i]);
5203         }
5204         
5205         
5206     };
5207     
5208     
5209
5210     return {
5211         /** True to force the use of DOM instead of html fragments @type Boolean */
5212         useDom : false,
5213     
5214         /**
5215          * Returns the markup for the passed Element(s) config
5216          * @param {Object} o The Dom object spec (and children)
5217          * @return {String}
5218          */
5219         markup : function(o){
5220             return createHtml(o);
5221         },
5222     
5223         /**
5224          * Applies a style specification to an element
5225          * @param {String/HTMLElement} el The element to apply styles to
5226          * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
5227          * a function which returns such a specification.
5228          */
5229         applyStyles : function(el, styles){
5230             if(styles){
5231                el = Roo.fly(el);
5232                if(typeof styles == "string"){
5233                    var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
5234                    var matches;
5235                    while ((matches = re.exec(styles)) != null){
5236                        el.setStyle(matches[1], matches[2]);
5237                    }
5238                }else if (typeof styles == "object"){
5239                    for (var style in styles){
5240                       el.setStyle(style, styles[style]);
5241                    }
5242                }else if (typeof styles == "function"){
5243                     Roo.DomHelper.applyStyles(el, styles.call());
5244                }
5245             }
5246         },
5247     
5248         /**
5249          * Inserts an HTML fragment into the Dom
5250          * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
5251          * @param {HTMLElement} el The context element
5252          * @param {String} html The HTML fragmenet
5253          * @return {HTMLElement} The new node
5254          */
5255         insertHtml : function(where, el, html){
5256             where = where.toLowerCase();
5257             if(el.insertAdjacentHTML){
5258                 if(tableRe.test(el.tagName)){
5259                     var rs;
5260                     if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
5261                         return rs;
5262                     }
5263                 }
5264                 switch(where){
5265                     case "beforebegin":
5266                         el.insertAdjacentHTML('BeforeBegin', html);
5267                         return el.previousSibling;
5268                     case "afterbegin":
5269                         el.insertAdjacentHTML('AfterBegin', html);
5270                         return el.firstChild;
5271                     case "beforeend":
5272                         el.insertAdjacentHTML('BeforeEnd', html);
5273                         return el.lastChild;
5274                     case "afterend":
5275                         el.insertAdjacentHTML('AfterEnd', html);
5276                         return el.nextSibling;
5277                 }
5278                 throw 'Illegal insertion point -> "' + where + '"';
5279             }
5280             var range = el.ownerDocument.createRange();
5281             var frag;
5282             switch(where){
5283                  case "beforebegin":
5284                     range.setStartBefore(el);
5285                     frag = range.createContextualFragment(html);
5286                     el.parentNode.insertBefore(frag, el);
5287                     return el.previousSibling;
5288                  case "afterbegin":
5289                     if(el.firstChild){
5290                         range.setStartBefore(el.firstChild);
5291                         frag = range.createContextualFragment(html);
5292                         el.insertBefore(frag, el.firstChild);
5293                         return el.firstChild;
5294                     }else{
5295                         el.innerHTML = html;
5296                         return el.firstChild;
5297                     }
5298                 case "beforeend":
5299                     if(el.lastChild){
5300                         range.setStartAfter(el.lastChild);
5301                         frag = range.createContextualFragment(html);
5302                         el.appendChild(frag);
5303                         return el.lastChild;
5304                     }else{
5305                         el.innerHTML = html;
5306                         return el.lastChild;
5307                     }
5308                 case "afterend":
5309                     range.setStartAfter(el);
5310                     frag = range.createContextualFragment(html);
5311                     el.parentNode.insertBefore(frag, el.nextSibling);
5312                     return el.nextSibling;
5313                 }
5314                 throw 'Illegal insertion point -> "' + where + '"';
5315         },
5316     
5317         /**
5318          * Creates new Dom element(s) and inserts them before el
5319          * @param {String/HTMLElement/Element} el The context element
5320          * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5321          * @param {Boolean} returnElement (optional) true to return a Roo.Element
5322          * @return {HTMLElement/Roo.Element} The new node
5323          */
5324         insertBefore : function(el, o, returnElement){
5325             return this.doInsert(el, o, returnElement, "beforeBegin");
5326         },
5327     
5328         /**
5329          * Creates new Dom element(s) and inserts them after el
5330          * @param {String/HTMLElement/Element} el The context element
5331          * @param {Object} o The Dom object spec (and children)
5332          * @param {Boolean} returnElement (optional) true to return a Roo.Element
5333          * @return {HTMLElement/Roo.Element} The new node
5334          */
5335         insertAfter : function(el, o, returnElement){
5336             return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
5337         },
5338     
5339         /**
5340          * Creates new Dom element(s) and inserts them as the first child of el
5341          * @param {String/HTMLElement/Element} el The context element
5342          * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5343          * @param {Boolean} returnElement (optional) true to return a Roo.Element
5344          * @return {HTMLElement/Roo.Element} The new node
5345          */
5346         insertFirst : function(el, o, returnElement){
5347             return this.doInsert(el, o, returnElement, "afterBegin");
5348         },
5349     
5350         // private
5351         doInsert : function(el, o, returnElement, pos, sibling){
5352             el = Roo.getDom(el);
5353             var newNode;
5354             if(this.useDom || o.ns){
5355                 newNode = createDom(o, null);
5356                 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
5357             }else{
5358                 var html = createHtml(o);
5359                 newNode = this.insertHtml(pos, el, html);
5360             }
5361             return returnElement ? Roo.get(newNode, true) : newNode;
5362         },
5363     
5364         /**
5365          * Creates new Dom element(s) and appends them to el
5366          * @param {String/HTMLElement/Element} el The context element
5367          * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5368          * @param {Boolean} returnElement (optional) true to return a Roo.Element
5369          * @return {HTMLElement/Roo.Element} The new node
5370          */
5371         append : function(el, o, returnElement){
5372             el = Roo.getDom(el);
5373             var newNode;
5374             if(this.useDom || o.ns){
5375                 newNode = createDom(o, null);
5376                 el.appendChild(newNode);
5377             }else{
5378                 var html = createHtml(o);
5379                 newNode = this.insertHtml("beforeEnd", el, html);
5380             }
5381             return returnElement ? Roo.get(newNode, true) : newNode;
5382         },
5383     
5384         /**
5385          * Creates new Dom element(s) and overwrites the contents of el with them
5386          * @param {String/HTMLElement/Element} el The context element
5387          * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5388          * @param {Boolean} returnElement (optional) true to return a Roo.Element
5389          * @return {HTMLElement/Roo.Element} The new node
5390          */
5391         overwrite : function(el, o, returnElement)
5392         {
5393             el = Roo.getDom(el);
5394             if (o.ns) {
5395               
5396                 while (el.childNodes.length) {
5397                     el.removeChild(el.firstChild);
5398                 }
5399                 createDom(o, el);
5400             } else {
5401                 el.innerHTML = createHtml(o);   
5402             }
5403             
5404             return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
5405         },
5406     
5407         /**
5408          * Creates a new Roo.DomHelper.Template from the Dom object spec
5409          * @param {Object} o The Dom object spec (and children)
5410          * @return {Roo.DomHelper.Template} The new template
5411          */
5412         createTemplate : function(o){
5413             var html = createHtml(o);
5414             return new Roo.Template(html);
5415         },
5416          /**
5417          * Updates the first element with the spec from the o (replacing if necessary)
5418          * This iterates through the children, and updates attributes / children etc..
5419          * @param {String/HTMLElement/Element} el The context element
5420          * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5421          */
5422         
5423         update : function(el, o)
5424         {
5425             updateNode(Roo.getDom(el), createDom(o));
5426             
5427         }
5428         
5429         
5430     };
5431 }();
5432 /*
5433  * Based on:
5434  * Ext JS Library 1.1.1
5435  * Copyright(c) 2006-2007, Ext JS, LLC.
5436  *
5437  * Originally Released Under LGPL - original licence link has changed is not relivant.
5438  *
5439  * Fork - LGPL
5440  * <script type="text/javascript">
5441  */
5442  
5443 /**
5444 * @class Roo.Template
5445 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
5446 * For a list of available format functions, see {@link Roo.util.Format}.<br />
5447 * Usage:
5448 <pre><code>
5449 var t = new Roo.Template({
5450     html :  '&lt;div name="{id}"&gt;' + 
5451         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
5452         '&lt;/div&gt;',
5453     myformat: function (value, allValues) {
5454         return 'XX' + value;
5455     }
5456 });
5457 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
5458 </code></pre>
5459 * For more information see this blog post with examples:
5460 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
5461      - Create Elements using DOM, HTML fragments and Templates</a>. 
5462 * @constructor
5463 * @param {Object} cfg - Configuration object.
5464 */
5465 Roo.Template = function(cfg){
5466     // BC!
5467     if(cfg instanceof Array){
5468         cfg = cfg.join("");
5469     }else if(arguments.length > 1){
5470         cfg = Array.prototype.join.call(arguments, "");
5471     }
5472     
5473     
5474     if (typeof(cfg) == 'object') {
5475         Roo.apply(this,cfg)
5476     } else {
5477         // bc
5478         this.html = cfg;
5479     }
5480     if (this.url) {
5481         this.load();
5482     }
5483     
5484 };
5485 Roo.Template.prototype = {
5486     
5487     /**
5488      * @cfg {Function} onLoad Called after the template has been loaded and complied (usually from a remove source)
5489      */
5490     onLoad : false,
5491     
5492     
5493     /**
5494      * @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..
5495      *                    it should be fixed so that template is observable...
5496      */
5497     url : false,
5498     /**
5499      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
5500      */
5501     html : '',
5502     
5503     
5504     compiled : false,
5505     loaded : false,
5506     /**
5507      * Returns an HTML fragment of this template with the specified values applied.
5508      * @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'})
5509      * @return {String} The HTML fragment
5510      */
5511     
5512    
5513     
5514     applyTemplate : function(values){
5515         //Roo.log(["applyTemplate", values]);
5516         try {
5517            
5518             if(this.compiled){
5519                 return this.compiled(values);
5520             }
5521             var useF = this.disableFormats !== true;
5522             var fm = Roo.util.Format, tpl = this;
5523             var fn = function(m, name, format, args){
5524                 if(format && useF){
5525                     if(format.substr(0, 5) == "this."){
5526                         return tpl.call(format.substr(5), values[name], values);
5527                     }else{
5528                         if(args){
5529                             // quoted values are required for strings in compiled templates, 
5530                             // but for non compiled we need to strip them
5531                             // quoted reversed for jsmin
5532                             var re = /^\s*['"](.*)["']\s*$/;
5533                             args = args.split(',');
5534                             for(var i = 0, len = args.length; i < len; i++){
5535                                 args[i] = args[i].replace(re, "$1");
5536                             }
5537                             args = [values[name]].concat(args);
5538                         }else{
5539                             args = [values[name]];
5540                         }
5541                         return fm[format].apply(fm, args);
5542                     }
5543                 }else{
5544                     return values[name] !== undefined ? values[name] : "";
5545                 }
5546             };
5547             return this.html.replace(this.re, fn);
5548         } catch (e) {
5549             Roo.log(e);
5550             throw e;
5551         }
5552          
5553     },
5554     
5555     loading : false,
5556       
5557     load : function ()
5558     {
5559          
5560         if (this.loading) {
5561             return;
5562         }
5563         var _t = this;
5564         
5565         this.loading = true;
5566         this.compiled = false;
5567         
5568         var cx = new Roo.data.Connection();
5569         cx.request({
5570             url : this.url,
5571             method : 'GET',
5572             success : function (response) {
5573                 _t.loading = false;
5574                 _t.url = false;
5575                 
5576                 _t.set(response.responseText,true);
5577                 _t.loaded = true;
5578                 if (_t.onLoad) {
5579                     _t.onLoad();
5580                 }
5581              },
5582             failure : function(response) {
5583                 Roo.log("Template failed to load from " + _t.url);
5584                 _t.loading = false;
5585             }
5586         });
5587     },
5588
5589     /**
5590      * Sets the HTML used as the template and optionally compiles it.
5591      * @param {String} html
5592      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
5593      * @return {Roo.Template} this
5594      */
5595     set : function(html, compile){
5596         this.html = html;
5597         this.compiled = false;
5598         if(compile){
5599             this.compile();
5600         }
5601         return this;
5602     },
5603     
5604     /**
5605      * True to disable format functions (defaults to false)
5606      * @type Boolean
5607      */
5608     disableFormats : false,
5609     
5610     /**
5611     * The regular expression used to match template variables 
5612     * @type RegExp
5613     * @property 
5614     */
5615     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
5616     
5617     /**
5618      * Compiles the template into an internal function, eliminating the RegEx overhead.
5619      * @return {Roo.Template} this
5620      */
5621     compile : function(){
5622         var fm = Roo.util.Format;
5623         var useF = this.disableFormats !== true;
5624         var sep = Roo.isGecko ? "+" : ",";
5625         var fn = function(m, name, format, args){
5626             if(format && useF){
5627                 args = args ? ',' + args : "";
5628                 if(format.substr(0, 5) != "this."){
5629                     format = "fm." + format + '(';
5630                 }else{
5631                     format = 'this.call("'+ format.substr(5) + '", ';
5632                     args = ", values";
5633                 }
5634             }else{
5635                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
5636             }
5637             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
5638         };
5639         var body;
5640         // branched to use + in gecko and [].join() in others
5641         if(Roo.isGecko){
5642             body = "this.compiled = function(values){ return '" +
5643                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
5644                     "';};";
5645         }else{
5646             body = ["this.compiled = function(values){ return ['"];
5647             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
5648             body.push("'].join('');};");
5649             body = body.join('');
5650         }
5651         /**
5652          * eval:var:values
5653          * eval:var:fm
5654          */
5655         eval(body);
5656         return this;
5657     },
5658     
5659     // private function used to call members
5660     call : function(fnName, value, allValues){
5661         return this[fnName](value, allValues);
5662     },
5663     
5664     /**
5665      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
5666      * @param {String/HTMLElement/Roo.Element} el The context element
5667      * @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'})
5668      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
5669      * @return {HTMLElement/Roo.Element} The new node or Element
5670      */
5671     insertFirst: function(el, values, returnElement){
5672         return this.doInsert('afterBegin', el, values, returnElement);
5673     },
5674
5675     /**
5676      * Applies the supplied values to the template and inserts the new node(s) before el.
5677      * @param {String/HTMLElement/Roo.Element} el The context element
5678      * @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'})
5679      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
5680      * @return {HTMLElement/Roo.Element} The new node or Element
5681      */
5682     insertBefore: function(el, values, returnElement){
5683         return this.doInsert('beforeBegin', el, values, returnElement);
5684     },
5685
5686     /**
5687      * Applies the supplied values to the template and inserts the new node(s) after el.
5688      * @param {String/HTMLElement/Roo.Element} el The context element
5689      * @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'})
5690      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
5691      * @return {HTMLElement/Roo.Element} The new node or Element
5692      */
5693     insertAfter : function(el, values, returnElement){
5694         return this.doInsert('afterEnd', el, values, returnElement);
5695     },
5696     
5697     /**
5698      * Applies the supplied values to the template and appends the new node(s) to el.
5699      * @param {String/HTMLElement/Roo.Element} el The context element
5700      * @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'})
5701      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
5702      * @return {HTMLElement/Roo.Element} The new node or Element
5703      */
5704     append : function(el, values, returnElement){
5705         return this.doInsert('beforeEnd', el, values, returnElement);
5706     },
5707
5708     doInsert : function(where, el, values, returnEl){
5709         el = Roo.getDom(el);
5710         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
5711         return returnEl ? Roo.get(newNode, true) : newNode;
5712     },
5713
5714     /**
5715      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
5716      * @param {String/HTMLElement/Roo.Element} el The context element
5717      * @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'})
5718      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
5719      * @return {HTMLElement/Roo.Element} The new node or Element
5720      */
5721     overwrite : function(el, values, returnElement){
5722         el = Roo.getDom(el);
5723         el.innerHTML = this.applyTemplate(values);
5724         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
5725     }
5726 };
5727 /**
5728  * Alias for {@link #applyTemplate}
5729  * @method
5730  */
5731 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
5732
5733 // backwards compat
5734 Roo.DomHelper.Template = Roo.Template;
5735
5736 /**
5737  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
5738  * @param {String/HTMLElement} el A DOM element or its id
5739  * @returns {Roo.Template} The created template
5740  * @static
5741  */
5742 Roo.Template.from = function(el){
5743     el = Roo.getDom(el);
5744     return new Roo.Template(el.value || el.innerHTML);
5745 };/*
5746  * Based on:
5747  * Ext JS Library 1.1.1
5748  * Copyright(c) 2006-2007, Ext JS, LLC.
5749  *
5750  * Originally Released Under LGPL - original licence link has changed is not relivant.
5751  *
5752  * Fork - LGPL
5753  * <script type="text/javascript">
5754  */
5755  
5756
5757 /*
5758  * This is code is also distributed under MIT license for use
5759  * with jQuery and prototype JavaScript libraries.
5760  */
5761 /**
5762  * @class Roo.DomQuery
5763 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).
5764 <p>
5765 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>
5766
5767 <p>
5768 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.
5769 </p>
5770 <h4>Element Selectors:</h4>
5771 <ul class="list">
5772     <li> <b>*</b> any element</li>
5773     <li> <b>E</b> an element with the tag E</li>
5774     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
5775     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
5776     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
5777     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
5778 </ul>
5779 <h4>Attribute Selectors:</h4>
5780 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
5781 <ul class="list">
5782     <li> <b>E[foo]</b> has an attribute "foo"</li>
5783     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
5784     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
5785     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
5786     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
5787     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
5788     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
5789 </ul>
5790 <h4>Pseudo Classes:</h4>
5791 <ul class="list">
5792     <li> <b>E:first-child</b> E is the first child of its parent</li>
5793     <li> <b>E:last-child</b> E is the last child of its parent</li>
5794     <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>
5795     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
5796     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
5797     <li> <b>E:only-child</b> E is the only child of its parent</li>
5798     <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>
5799     <li> <b>E:first</b> the first E in the resultset</li>
5800     <li> <b>E:last</b> the last E in the resultset</li>
5801     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
5802     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
5803     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
5804     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
5805     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
5806     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
5807     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
5808     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
5809     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
5810 </ul>
5811 <h4>CSS Value Selectors:</h4>
5812 <ul class="list">
5813     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
5814     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
5815     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
5816     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
5817     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
5818     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
5819 </ul>
5820  * @static
5821  */
5822 Roo.DomQuery = function(){
5823     var cache = {}, simpleCache = {}, valueCache = {};
5824     var nonSpace = /\S/;
5825     var trimRe = /^\s+|\s+$/g;
5826     var tplRe = /\{(\d+)\}/g;
5827     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
5828     var tagTokenRe = /^(#)?([\w-\*]+)/;
5829     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
5830
5831     function child(p, index){
5832         var i = 0;
5833         var n = p.firstChild;
5834         while(n){
5835             if(n.nodeType == 1){
5836                if(++i == index){
5837                    return n;
5838                }
5839             }
5840             n = n.nextSibling;
5841         }
5842         return null;
5843     };
5844
5845     function next(n){
5846         while((n = n.nextSibling) && n.nodeType != 1);
5847         return n;
5848     };
5849
5850     function prev(n){
5851         while((n = n.previousSibling) && n.nodeType != 1);
5852         return n;
5853     };
5854
5855     function children(d){
5856         var n = d.firstChild, ni = -1;
5857             while(n){
5858                 var nx = n.nextSibling;
5859                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
5860                     d.removeChild(n);
5861                 }else{
5862                     n.nodeIndex = ++ni;
5863                 }
5864                 n = nx;
5865             }
5866             return this;
5867         };
5868
5869     function byClassName(c, a, v){
5870         if(!v){
5871             return c;
5872         }
5873         var r = [], ri = -1, cn;
5874         for(var i = 0, ci; ci = c[i]; i++){
5875             
5876             
5877             if((' '+
5878                 ( (ci instanceof SVGElement) ? ci.className.baseVal : ci.className)
5879                  +' ').indexOf(v) != -1){
5880                 r[++ri] = ci;
5881             }
5882         }
5883         return r;
5884     };
5885
5886     function attrValue(n, attr){
5887         if(!n.tagName && typeof n.length != "undefined"){
5888             n = n[0];
5889         }
5890         if(!n){
5891             return null;
5892         }
5893         if(attr == "for"){
5894             return n.htmlFor;
5895         }
5896         if(attr == "class" || attr == "className"){
5897             return (n instanceof SVGElement) ? n.className.baseVal : n.className;
5898         }
5899         return n.getAttribute(attr) || n[attr];
5900
5901     };
5902
5903     function getNodes(ns, mode, tagName){
5904         var result = [], ri = -1, cs;
5905         if(!ns){
5906             return result;
5907         }
5908         tagName = tagName || "*";
5909         if(typeof ns.getElementsByTagName != "undefined"){
5910             ns = [ns];
5911         }
5912         if(!mode){
5913             for(var i = 0, ni; ni = ns[i]; i++){
5914                 cs = ni.getElementsByTagName(tagName);
5915                 for(var j = 0, ci; ci = cs[j]; j++){
5916                     result[++ri] = ci;
5917                 }
5918             }
5919         }else if(mode == "/" || mode == ">"){
5920             var utag = tagName.toUpperCase();
5921             for(var i = 0, ni, cn; ni = ns[i]; i++){
5922                 cn = ni.children || ni.childNodes;
5923                 for(var j = 0, cj; cj = cn[j]; j++){
5924                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
5925                         result[++ri] = cj;
5926                     }
5927                 }
5928             }
5929         }else if(mode == "+"){
5930             var utag = tagName.toUpperCase();
5931             for(var i = 0, n; n = ns[i]; i++){
5932                 while((n = n.nextSibling) && n.nodeType != 1);
5933                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5934                     result[++ri] = n;
5935                 }
5936             }
5937         }else if(mode == "~"){
5938             for(var i = 0, n; n = ns[i]; i++){
5939                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5940                 if(n){
5941                     result[++ri] = n;
5942                 }
5943             }
5944         }
5945         return result;
5946     };
5947
5948     function concat(a, b){
5949         if(b.slice){
5950             return a.concat(b);
5951         }
5952         for(var i = 0, l = b.length; i < l; i++){
5953             a[a.length] = b[i];
5954         }
5955         return a;
5956     }
5957
5958     function byTag(cs, tagName){
5959         if(cs.tagName || cs == document){
5960             cs = [cs];
5961         }
5962         if(!tagName){
5963             return cs;
5964         }
5965         var r = [], ri = -1;
5966         tagName = tagName.toLowerCase();
5967         for(var i = 0, ci; ci = cs[i]; i++){
5968             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5969                 r[++ri] = ci;
5970             }
5971         }
5972         return r;
5973     };
5974
5975     function byId(cs, attr, id){
5976         if(cs.tagName || cs == document){
5977             cs = [cs];
5978         }
5979         if(!id){
5980             return cs;
5981         }
5982         var r = [], ri = -1;
5983         for(var i = 0,ci; ci = cs[i]; i++){
5984             if(ci && ci.id == id){
5985                 r[++ri] = ci;
5986                 return r;
5987             }
5988         }
5989         return r;
5990     };
5991
5992     function byAttribute(cs, attr, value, op, custom){
5993         var r = [], ri = -1, st = custom=="{";
5994         var f = Roo.DomQuery.operators[op];
5995         for(var i = 0, ci; ci = cs[i]; i++){
5996             var a;
5997             if(st){
5998                 a = Roo.DomQuery.getStyle(ci, attr);
5999             }
6000             else if(attr == "class" || attr == "className"){
6001                 a = (ci instanceof SVGElement) ? ci.className.baseVal : ci.className;
6002             }else if(attr == "for"){
6003                 a = ci.htmlFor;
6004             }else if(attr == "href"){
6005                 a = ci.getAttribute("href", 2);
6006             }else{
6007                 a = ci.getAttribute(attr);
6008             }
6009             if((f && f(a, value)) || (!f && a)){
6010                 r[++ri] = ci;
6011             }
6012         }
6013         return r;
6014     };
6015
6016     function byPseudo(cs, name, value){
6017         return Roo.DomQuery.pseudos[name](cs, value);
6018     };
6019
6020     // This is for IE MSXML which does not support expandos.
6021     // IE runs the same speed using setAttribute, however FF slows way down
6022     // and Safari completely fails so they need to continue to use expandos.
6023     var isIE = window.ActiveXObject ? true : false;
6024
6025     // this eval is stop the compressor from
6026     // renaming the variable to something shorter
6027     
6028     /** eval:var:batch */
6029     var batch = 30803; 
6030
6031     var key = 30803;
6032
6033     function nodupIEXml(cs){
6034         var d = ++key;
6035         cs[0].setAttribute("_nodup", d);
6036         var r = [cs[0]];
6037         for(var i = 1, len = cs.length; i < len; i++){
6038             var c = cs[i];
6039             if(!c.getAttribute("_nodup") != d){
6040                 c.setAttribute("_nodup", d);
6041                 r[r.length] = c;
6042             }
6043         }
6044         for(var i = 0, len = cs.length; i < len; i++){
6045             cs[i].removeAttribute("_nodup");
6046         }
6047         return r;
6048     }
6049
6050     function nodup(cs){
6051         if(!cs){
6052             return [];
6053         }
6054         var len = cs.length, c, i, r = cs, cj, ri = -1;
6055         if(!len || typeof cs.nodeType != "undefined" || len == 1){
6056             return cs;
6057         }
6058         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
6059             return nodupIEXml(cs);
6060         }
6061         var d = ++key;
6062         cs[0]._nodup = d;
6063         for(i = 1; c = cs[i]; i++){
6064             if(c._nodup != d){
6065                 c._nodup = d;
6066             }else{
6067                 r = [];
6068                 for(var j = 0; j < i; j++){
6069                     r[++ri] = cs[j];
6070                 }
6071                 for(j = i+1; cj = cs[j]; j++){
6072                     if(cj._nodup != d){
6073                         cj._nodup = d;
6074                         r[++ri] = cj;
6075                     }
6076                 }
6077                 return r;
6078             }
6079         }
6080         return r;
6081     }
6082
6083     function quickDiffIEXml(c1, c2){
6084         var d = ++key;
6085         for(var i = 0, len = c1.length; i < len; i++){
6086             c1[i].setAttribute("_qdiff", d);
6087         }
6088         var r = [];
6089         for(var i = 0, len = c2.length; i < len; i++){
6090             if(c2[i].getAttribute("_qdiff") != d){
6091                 r[r.length] = c2[i];
6092             }
6093         }
6094         for(var i = 0, len = c1.length; i < len; i++){
6095            c1[i].removeAttribute("_qdiff");
6096         }
6097         return r;
6098     }
6099
6100     function quickDiff(c1, c2){
6101         var len1 = c1.length;
6102         if(!len1){
6103             return c2;
6104         }
6105         if(isIE && c1[0].selectSingleNode){
6106             return quickDiffIEXml(c1, c2);
6107         }
6108         var d = ++key;
6109         for(var i = 0; i < len1; i++){
6110             c1[i]._qdiff = d;
6111         }
6112         var r = [];
6113         for(var i = 0, len = c2.length; i < len; i++){
6114             if(c2[i]._qdiff != d){
6115                 r[r.length] = c2[i];
6116             }
6117         }
6118         return r;
6119     }
6120
6121     function quickId(ns, mode, root, id){
6122         if(ns == root){
6123            var d = root.ownerDocument || root;
6124            return d.getElementById(id);
6125         }
6126         ns = getNodes(ns, mode, "*");
6127         return byId(ns, null, id);
6128     }
6129
6130     return {
6131         getStyle : function(el, name){
6132             return Roo.fly(el).getStyle(name);
6133         },
6134         /**
6135          * Compiles a selector/xpath query into a reusable function. The returned function
6136          * takes one parameter "root" (optional), which is the context node from where the query should start.
6137          * @param {String} selector The selector/xpath query
6138          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
6139          * @return {Function}
6140          */
6141         compile : function(path, type){
6142             type = type || "select";
6143             
6144             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
6145             var q = path, mode, lq;
6146             var tk = Roo.DomQuery.matchers;
6147             var tklen = tk.length;
6148             var mm;
6149
6150             // accept leading mode switch
6151             var lmode = q.match(modeRe);
6152             if(lmode && lmode[1]){
6153                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
6154                 q = q.replace(lmode[1], "");
6155             }
6156             // strip leading slashes
6157             while(path.substr(0, 1)=="/"){
6158                 path = path.substr(1);
6159             }
6160
6161             while(q && lq != q){
6162                 lq = q;
6163                 var tm = q.match(tagTokenRe);
6164                 if(type == "select"){
6165                     if(tm){
6166                         if(tm[1] == "#"){
6167                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
6168                         }else{
6169                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
6170                         }
6171                         q = q.replace(tm[0], "");
6172                     }else if(q.substr(0, 1) != '@'){
6173                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
6174                     }
6175                 }else{
6176                     if(tm){
6177                         if(tm[1] == "#"){
6178                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
6179                         }else{
6180                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
6181                         }
6182                         q = q.replace(tm[0], "");
6183                     }
6184                 }
6185                 while(!(mm = q.match(modeRe))){
6186                     var matched = false;
6187                     for(var j = 0; j < tklen; j++){
6188                         var t = tk[j];
6189                         var m = q.match(t.re);
6190                         if(m){
6191                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
6192                                                     return m[i];
6193                                                 });
6194                             q = q.replace(m[0], "");
6195                             matched = true;
6196                             break;
6197                         }
6198                     }
6199                     // prevent infinite loop on bad selector
6200                     if(!matched){
6201                         throw 'Error parsing selector, parsing failed at "' + q + '"';
6202                     }
6203                 }
6204                 if(mm[1]){
6205                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
6206                     q = q.replace(mm[1], "");
6207                 }
6208             }
6209             fn[fn.length] = "return nodup(n);\n}";
6210             
6211              /** 
6212               * list of variables that need from compression as they are used by eval.
6213              *  eval:var:batch 
6214              *  eval:var:nodup
6215              *  eval:var:byTag
6216              *  eval:var:ById
6217              *  eval:var:getNodes
6218              *  eval:var:quickId
6219              *  eval:var:mode
6220              *  eval:var:root
6221              *  eval:var:n
6222              *  eval:var:byClassName
6223              *  eval:var:byPseudo
6224              *  eval:var:byAttribute
6225              *  eval:var:attrValue
6226              * 
6227              **/ 
6228             eval(fn.join(""));
6229             return f;
6230         },
6231
6232         /**
6233          * Selects a group of elements.
6234          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
6235          * @param {Node} root (optional) The start of the query (defaults to document).
6236          * @return {Array}
6237          */
6238         select : function(path, root, type){
6239             if(!root || root == document){
6240                 root = document;
6241             }
6242             if(typeof root == "string"){
6243                 root = document.getElementById(root);
6244             }
6245             var paths = path.split(",");
6246             var results = [];
6247             for(var i = 0, len = paths.length; i < len; i++){
6248                 var p = paths[i].replace(trimRe, "");
6249                 if(!cache[p]){
6250                     cache[p] = Roo.DomQuery.compile(p);
6251                     if(!cache[p]){
6252                         throw p + " is not a valid selector";
6253                     }
6254                 }
6255                 var result = cache[p](root);
6256                 if(result && result != document){
6257                     results = results.concat(result);
6258                 }
6259             }
6260             if(paths.length > 1){
6261                 return nodup(results);
6262             }
6263             return results;
6264         },
6265
6266         /**
6267          * Selects a single element.
6268          * @param {String} selector The selector/xpath query
6269          * @param {Node} root (optional) The start of the query (defaults to document).
6270          * @return {Element}
6271          */
6272         selectNode : function(path, root){
6273             return Roo.DomQuery.select(path, root)[0];
6274         },
6275
6276         /**
6277          * Selects the value of a node, optionally replacing null with the defaultValue.
6278          * @param {String} selector The selector/xpath query
6279          * @param {Node} root (optional) The start of the query (defaults to document).
6280          * @param {String} defaultValue
6281          */
6282         selectValue : function(path, root, defaultValue){
6283             path = path.replace(trimRe, "");
6284             if(!valueCache[path]){
6285                 valueCache[path] = Roo.DomQuery.compile(path, "select");
6286             }
6287             var n = valueCache[path](root);
6288             n = n[0] ? n[0] : n;
6289             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
6290             return ((v === null||v === undefined||v==='') ? defaultValue : v);
6291         },
6292
6293         /**
6294          * Selects the value of a node, parsing integers and floats.
6295          * @param {String} selector The selector/xpath query
6296          * @param {Node} root (optional) The start of the query (defaults to document).
6297          * @param {Number} defaultValue
6298          * @return {Number}
6299          */
6300         selectNumber : function(path, root, defaultValue){
6301             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
6302             return parseFloat(v);
6303         },
6304
6305         /**
6306          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
6307          * @param {String/HTMLElement/Array} el An element id, element or array of elements
6308          * @param {String} selector The simple selector to test
6309          * @return {Boolean}
6310          */
6311         is : function(el, ss){
6312             if(typeof el == "string"){
6313                 el = document.getElementById(el);
6314             }
6315             var isArray = (el instanceof Array);
6316             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
6317             return isArray ? (result.length == el.length) : (result.length > 0);
6318         },
6319
6320         /**
6321          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
6322          * @param {Array} el An array of elements to filter
6323          * @param {String} selector The simple selector to test
6324          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
6325          * the selector instead of the ones that match
6326          * @return {Array}
6327          */
6328         filter : function(els, ss, nonMatches){
6329             ss = ss.replace(trimRe, "");
6330             if(!simpleCache[ss]){
6331                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
6332             }
6333             var result = simpleCache[ss](els);
6334             return nonMatches ? quickDiff(result, els) : result;
6335         },
6336
6337         /**
6338          * Collection of matching regular expressions and code snippets.
6339          */
6340         matchers : [{
6341                 re: /^\.([\w-]+)/,
6342                 select: 'n = byClassName(n, null, " {1} ");'
6343             }, {
6344                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
6345                 select: 'n = byPseudo(n, "{1}", "{2}");'
6346             },{
6347                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
6348                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
6349             }, {
6350                 re: /^#([\w-]+)/,
6351                 select: 'n = byId(n, null, "{1}");'
6352             },{
6353                 re: /^@([\w-]+)/,
6354                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
6355             }
6356         ],
6357
6358         /**
6359          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
6360          * 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;.
6361          */
6362         operators : {
6363             "=" : function(a, v){
6364                 return a == v;
6365             },
6366             "!=" : function(a, v){
6367                 return a != v;
6368             },
6369             "^=" : function(a, v){
6370                 return a && a.substr(0, v.length) == v;
6371             },
6372             "$=" : function(a, v){
6373                 return a && a.substr(a.length-v.length) == v;
6374             },
6375             "*=" : function(a, v){
6376                 return a && a.indexOf(v) !== -1;
6377             },
6378             "%=" : function(a, v){
6379                 return (a % v) == 0;
6380             },
6381             "|=" : function(a, v){
6382                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
6383             },
6384             "~=" : function(a, v){
6385                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
6386             }
6387         },
6388
6389         /**
6390          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
6391          * and the argument (if any) supplied in the selector.
6392          */
6393         pseudos : {
6394             "first-child" : function(c){
6395                 var r = [], ri = -1, n;
6396                 for(var i = 0, ci; ci = n = c[i]; i++){
6397                     while((n = n.previousSibling) && n.nodeType != 1);
6398                     if(!n){
6399                         r[++ri] = ci;
6400                     }
6401                 }
6402                 return r;
6403             },
6404
6405             "last-child" : function(c){
6406                 var r = [], ri = -1, n;
6407                 for(var i = 0, ci; ci = n = c[i]; i++){
6408                     while((n = n.nextSibling) && n.nodeType != 1);
6409                     if(!n){
6410                         r[++ri] = ci;
6411                     }
6412                 }
6413                 return r;
6414             },
6415
6416             "nth-child" : function(c, a) {
6417                 var r = [], ri = -1;
6418                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
6419                 var f = (m[1] || 1) - 0, l = m[2] - 0;
6420                 for(var i = 0, n; n = c[i]; i++){
6421                     var pn = n.parentNode;
6422                     if (batch != pn._batch) {
6423                         var j = 0;
6424                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
6425                             if(cn.nodeType == 1){
6426                                cn.nodeIndex = ++j;
6427                             }
6428                         }
6429                         pn._batch = batch;
6430                     }
6431                     if (f == 1) {
6432                         if (l == 0 || n.nodeIndex == l){
6433                             r[++ri] = n;
6434                         }
6435                     } else if ((n.nodeIndex + l) % f == 0){
6436                         r[++ri] = n;
6437                     }
6438                 }
6439
6440                 return r;
6441             },
6442
6443             "only-child" : function(c){
6444                 var r = [], ri = -1;;
6445                 for(var i = 0, ci; ci = c[i]; i++){
6446                     if(!prev(ci) && !next(ci)){
6447                         r[++ri] = ci;
6448                     }
6449                 }
6450                 return r;
6451             },
6452
6453             "empty" : function(c){
6454                 var r = [], ri = -1;
6455                 for(var i = 0, ci; ci = c[i]; i++){
6456                     var cns = ci.childNodes, j = 0, cn, empty = true;
6457                     while(cn = cns[j]){
6458                         ++j;
6459                         if(cn.nodeType == 1 || cn.nodeType == 3){
6460                             empty = false;
6461                             break;
6462                         }
6463                     }
6464                     if(empty){
6465                         r[++ri] = ci;
6466                     }
6467                 }
6468                 return r;
6469             },
6470
6471             "contains" : function(c, v){
6472                 var r = [], ri = -1;
6473                 for(var i = 0, ci; ci = c[i]; i++){
6474                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
6475                         r[++ri] = ci;
6476                     }
6477                 }
6478                 return r;
6479             },
6480
6481             "nodeValue" : function(c, v){
6482                 var r = [], ri = -1;
6483                 for(var i = 0, ci; ci = c[i]; i++){
6484                     if(ci.firstChild && ci.firstChild.nodeValue == v){
6485                         r[++ri] = ci;
6486                     }
6487                 }
6488                 return r;
6489             },
6490
6491             "checked" : function(c){
6492                 var r = [], ri = -1;
6493                 for(var i = 0, ci; ci = c[i]; i++){
6494                     if(ci.checked == true){
6495                         r[++ri] = ci;
6496                     }
6497                 }
6498                 return r;
6499             },
6500
6501             "not" : function(c, ss){
6502                 return Roo.DomQuery.filter(c, ss, true);
6503             },
6504
6505             "odd" : function(c){
6506                 return this["nth-child"](c, "odd");
6507             },
6508
6509             "even" : function(c){
6510                 return this["nth-child"](c, "even");
6511             },
6512
6513             "nth" : function(c, a){
6514                 return c[a-1] || [];
6515             },
6516
6517             "first" : function(c){
6518                 return c[0] || [];
6519             },
6520
6521             "last" : function(c){
6522                 return c[c.length-1] || [];
6523             },
6524
6525             "has" : function(c, ss){
6526                 var s = Roo.DomQuery.select;
6527                 var r = [], ri = -1;
6528                 for(var i = 0, ci; ci = c[i]; i++){
6529                     if(s(ss, ci).length > 0){
6530                         r[++ri] = ci;
6531                     }
6532                 }
6533                 return r;
6534             },
6535
6536             "next" : function(c, ss){
6537                 var is = Roo.DomQuery.is;
6538                 var r = [], ri = -1;
6539                 for(var i = 0, ci; ci = c[i]; i++){
6540                     var n = next(ci);
6541                     if(n && is(n, ss)){
6542                         r[++ri] = ci;
6543                     }
6544                 }
6545                 return r;
6546             },
6547
6548             "prev" : function(c, ss){
6549                 var is = Roo.DomQuery.is;
6550                 var r = [], ri = -1;
6551                 for(var i = 0, ci; ci = c[i]; i++){
6552                     var n = prev(ci);
6553                     if(n && is(n, ss)){
6554                         r[++ri] = ci;
6555                     }
6556                 }
6557                 return r;
6558             }
6559         }
6560     };
6561 }();
6562
6563 /**
6564  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
6565  * @param {String} path The selector/xpath query
6566  * @param {Node} root (optional) The start of the query (defaults to document).
6567  * @return {Array}
6568  * @member Roo
6569  * @method query
6570  */
6571 Roo.query = Roo.DomQuery.select;
6572 /*
6573  * Based on:
6574  * Ext JS Library 1.1.1
6575  * Copyright(c) 2006-2007, Ext JS, LLC.
6576  *
6577  * Originally Released Under LGPL - original licence link has changed is not relivant.
6578  *
6579  * Fork - LGPL
6580  * <script type="text/javascript">
6581  */
6582
6583 /**
6584  * @class Roo.util.Observable
6585  * Base class that provides a common interface for publishing events. Subclasses are expected to
6586  * to have a property "events" with all the events defined.<br>
6587  * For example:
6588  * <pre><code>
6589  Employee = function(name){
6590     this.name = name;
6591     this.addEvents({
6592         "fired" : true,
6593         "quit" : true
6594     });
6595  }
6596  Roo.extend(Employee, Roo.util.Observable);
6597 </code></pre>
6598  * @param {Object} config properties to use (incuding events / listeners)
6599  */
6600
6601 Roo.util.Observable = function(cfg){
6602     
6603     cfg = cfg|| {};
6604     this.addEvents(cfg.events || {});
6605     if (cfg.events) {
6606         delete cfg.events; // make sure
6607     }
6608      
6609     Roo.apply(this, cfg);
6610     
6611     if(this.listeners){
6612         this.on(this.listeners);
6613         delete this.listeners;
6614     }
6615 };
6616 Roo.util.Observable.prototype = {
6617     /** 
6618  * @cfg {Object} listeners  list of events and functions to call for this object, 
6619  * For example :
6620  * <pre><code>
6621     listeners :  { 
6622        'click' : function(e) {
6623            ..... 
6624         } ,
6625         .... 
6626     } 
6627   </code></pre>
6628  */
6629     
6630     
6631     /**
6632      * Fires the specified event with the passed parameters (minus the event name).
6633      * @param {String} eventName
6634      * @param {Object...} args Variable number of parameters are passed to handlers
6635      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
6636      */
6637     fireEvent : function(){
6638         var ce = this.events[arguments[0].toLowerCase()];
6639         if(typeof ce == "object"){
6640             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
6641         }else{
6642             return true;
6643         }
6644     },
6645
6646     // private
6647     filterOptRe : /^(?:scope|delay|buffer|single)$/,
6648
6649     /**
6650      * Appends an event handler to this component
6651      * @param {String}   eventName The type of event to listen for
6652      * @param {Function} handler The method the event invokes
6653      * @param {Object}   scope (optional) The scope in which to execute the handler
6654      * function. The handler function's "this" context.
6655      * @param {Object}   options (optional) An object containing handler configuration
6656      * properties. This may contain any of the following properties:<ul>
6657      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6658      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6659      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6660      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6661      * by the specified number of milliseconds. If the event fires again within that time, the original
6662      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6663      * </ul><br>
6664      * <p>
6665      * <b>Combining Options</b><br>
6666      * Using the options argument, it is possible to combine different types of listeners:<br>
6667      * <br>
6668      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
6669                 <pre><code>
6670                 el.on('click', this.onClick, this, {
6671                         single: true,
6672                 delay: 100,
6673                 forumId: 4
6674                 });
6675                 </code></pre>
6676      * <p>
6677      * <b>Attaching multiple handlers in 1 call</b><br>
6678      * The method also allows for a single argument to be passed which is a config object containing properties
6679      * which specify multiple handlers.
6680      * <pre><code>
6681                 el.on({
6682                         'click': {
6683                         fn: this.onClick,
6684                         scope: this,
6685                         delay: 100
6686                 }, 
6687                 'mouseover': {
6688                         fn: this.onMouseOver,
6689                         scope: this
6690                 },
6691                 'mouseout': {
6692                         fn: this.onMouseOut,
6693                         scope: this
6694                 }
6695                 });
6696                 </code></pre>
6697      * <p>
6698      * Or a shorthand syntax which passes the same scope object to all handlers:
6699         <pre><code>
6700                 el.on({
6701                         'click': this.onClick,
6702                 'mouseover': this.onMouseOver,
6703                 'mouseout': this.onMouseOut,
6704                 scope: this
6705                 });
6706                 </code></pre>
6707      */
6708     addListener : function(eventName, fn, scope, o){
6709         if(typeof eventName == "object"){
6710             o = eventName;
6711             for(var e in o){
6712                 if(this.filterOptRe.test(e)){
6713                     continue;
6714                 }
6715                 if(typeof o[e] == "function"){
6716                     // shared options
6717                     this.addListener(e, o[e], o.scope,  o);
6718                 }else{
6719                     // individual options
6720                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
6721                 }
6722             }
6723             return;
6724         }
6725         o = (!o || typeof o == "boolean") ? {} : o;
6726         eventName = eventName.toLowerCase();
6727         var ce = this.events[eventName] || true;
6728         if(typeof ce == "boolean"){
6729             ce = new Roo.util.Event(this, eventName);
6730             this.events[eventName] = ce;
6731         }
6732         ce.addListener(fn, scope, o);
6733     },
6734
6735     /**
6736      * Removes a listener
6737      * @param {String}   eventName     The type of event to listen for
6738      * @param {Function} handler        The handler to remove
6739      * @param {Object}   scope  (optional) The scope (this object) for the handler
6740      */
6741     removeListener : function(eventName, fn, scope){
6742         var ce = this.events[eventName.toLowerCase()];
6743         if(typeof ce == "object"){
6744             ce.removeListener(fn, scope);
6745         }
6746     },
6747
6748     /**
6749      * Removes all listeners for this object
6750      */
6751     purgeListeners : function(){
6752         for(var evt in this.events){
6753             if(typeof this.events[evt] == "object"){
6754                  this.events[evt].clearListeners();
6755             }
6756         }
6757     },
6758
6759     relayEvents : function(o, events){
6760         var createHandler = function(ename){
6761             return function(){
6762                  
6763                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
6764             };
6765         };
6766         for(var i = 0, len = events.length; i < len; i++){
6767             var ename = events[i];
6768             if(!this.events[ename]){
6769                 this.events[ename] = true;
6770             };
6771             o.on(ename, createHandler(ename), this);
6772         }
6773     },
6774
6775     /**
6776      * Used to define events on this Observable
6777      * @param {Object} object The object with the events defined
6778      */
6779     addEvents : function(o){
6780         if(!this.events){
6781             this.events = {};
6782         }
6783         Roo.applyIf(this.events, o);
6784     },
6785
6786     /**
6787      * Checks to see if this object has any listeners for a specified event
6788      * @param {String} eventName The name of the event to check for
6789      * @return {Boolean} True if the event is being listened for, else false
6790      */
6791     hasListener : function(eventName){
6792         var e = this.events[eventName];
6793         return typeof e == "object" && e.listeners.length > 0;
6794     }
6795 };
6796 /**
6797  * Appends an event handler to this element (shorthand for addListener)
6798  * @param {String}   eventName     The type of event to listen for
6799  * @param {Function} handler        The method the event invokes
6800  * @param {Object}   scope (optional) The scope in which to execute the handler
6801  * function. The handler function's "this" context.
6802  * @param {Object}   options  (optional)
6803  * @method
6804  */
6805 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
6806 /**
6807  * Removes a listener (shorthand for removeListener)
6808  * @param {String}   eventName     The type of event to listen for
6809  * @param {Function} handler        The handler to remove
6810  * @param {Object}   scope  (optional) The scope (this object) for the handler
6811  * @method
6812  */
6813 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
6814
6815 /**
6816  * Starts capture on the specified Observable. All events will be passed
6817  * to the supplied function with the event name + standard signature of the event
6818  * <b>before</b> the event is fired. If the supplied function returns false,
6819  * the event will not fire.
6820  * @param {Observable} o The Observable to capture
6821  * @param {Function} fn The function to call
6822  * @param {Object} scope (optional) The scope (this object) for the fn
6823  * @static
6824  */
6825 Roo.util.Observable.capture = function(o, fn, scope){
6826     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
6827 };
6828
6829 /**
6830  * Removes <b>all</b> added captures from the Observable.
6831  * @param {Observable} o The Observable to release
6832  * @static
6833  */
6834 Roo.util.Observable.releaseCapture = function(o){
6835     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
6836 };
6837
6838 (function(){
6839
6840     var createBuffered = function(h, o, scope){
6841         var task = new Roo.util.DelayedTask();
6842         return function(){
6843             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
6844         };
6845     };
6846
6847     var createSingle = function(h, e, fn, scope){
6848         return function(){
6849             e.removeListener(fn, scope);
6850             return h.apply(scope, arguments);
6851         };
6852     };
6853
6854     var createDelayed = function(h, o, scope){
6855         return function(){
6856             var args = Array.prototype.slice.call(arguments, 0);
6857             setTimeout(function(){
6858                 h.apply(scope, args);
6859             }, o.delay || 10);
6860         };
6861     };
6862
6863     Roo.util.Event = function(obj, name){
6864         this.name = name;
6865         this.obj = obj;
6866         this.listeners = [];
6867     };
6868
6869     Roo.util.Event.prototype = {
6870         addListener : function(fn, scope, options){
6871             var o = options || {};
6872             scope = scope || this.obj;
6873             if(!this.isListening(fn, scope)){
6874                 var l = {fn: fn, scope: scope, options: o};
6875                 var h = fn;
6876                 if(o.delay){
6877                     h = createDelayed(h, o, scope);
6878                 }
6879                 if(o.single){
6880                     h = createSingle(h, this, fn, scope);
6881                 }
6882                 if(o.buffer){
6883                     h = createBuffered(h, o, scope);
6884                 }
6885                 l.fireFn = h;
6886                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
6887                     this.listeners.push(l);
6888                 }else{
6889                     this.listeners = this.listeners.slice(0);
6890                     this.listeners.push(l);
6891                 }
6892             }
6893         },
6894
6895         findListener : function(fn, scope){
6896             scope = scope || this.obj;
6897             var ls = this.listeners;
6898             for(var i = 0, len = ls.length; i < len; i++){
6899                 var l = ls[i];
6900                 if(l.fn == fn && l.scope == scope){
6901                     return i;
6902                 }
6903             }
6904             return -1;
6905         },
6906
6907         isListening : function(fn, scope){
6908             return this.findListener(fn, scope) != -1;
6909         },
6910
6911         removeListener : function(fn, scope){
6912             var index;
6913             if((index = this.findListener(fn, scope)) != -1){
6914                 if(!this.firing){
6915                     this.listeners.splice(index, 1);
6916                 }else{
6917                     this.listeners = this.listeners.slice(0);
6918                     this.listeners.splice(index, 1);
6919                 }
6920                 return true;
6921             }
6922             return false;
6923         },
6924
6925         clearListeners : function(){
6926             this.listeners = [];
6927         },
6928
6929         fire : function(){
6930             var ls = this.listeners, scope, len = ls.length;
6931             if(len > 0){
6932                 this.firing = true;
6933                 var args = Array.prototype.slice.call(arguments, 0);                
6934                 for(var i = 0; i < len; i++){
6935                     var l = ls[i];
6936                     if(l.fireFn.apply(l.scope||this.obj||window, args) === false){
6937                         this.firing = false;
6938                         return false;
6939                     }
6940                 }
6941                 this.firing = false;
6942             }
6943             return true;
6944         }
6945     };
6946 })();/*
6947  * RooJS Library 
6948  * Copyright(c) 2007-2017, Roo J Solutions Ltd
6949  *
6950  * Licence LGPL 
6951  *
6952  */
6953  
6954 /**
6955  * @class Roo.Document
6956  * @extends Roo.util.Observable
6957  * This is a convience class to wrap up the main document loading code.. , rather than adding Roo.onReady(......)
6958  * 
6959  * @param {Object} config the methods and properties of the 'base' class for the application.
6960  * 
6961  *  Generic Page handler - implement this to start your app..
6962  * 
6963  * eg.
6964  *  MyProject = new Roo.Document({
6965         events : {
6966             'load' : true // your events..
6967         },
6968         listeners : {
6969             'ready' : function() {
6970                 // fired on Roo.onReady()
6971             }
6972         }
6973  * 
6974  */
6975 Roo.Document = function(cfg) {
6976      
6977     this.addEvents({ 
6978         'ready' : true
6979     });
6980     Roo.util.Observable.call(this,cfg);
6981     
6982     var _this = this;
6983     
6984     Roo.onReady(function() {
6985         _this.fireEvent('ready');
6986     },null,false);
6987     
6988     
6989 }
6990
6991 Roo.extend(Roo.Document, Roo.util.Observable, {});/*
6992  * Based on:
6993  * Ext JS Library 1.1.1
6994  * Copyright(c) 2006-2007, Ext JS, LLC.
6995  *
6996  * Originally Released Under LGPL - original licence link has changed is not relivant.
6997  *
6998  * Fork - LGPL
6999  * <script type="text/javascript">
7000  */
7001
7002 /**
7003  * @class Roo.EventManager
7004  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
7005  * several useful events directly.
7006  * See {@link Roo.EventObject} for more details on normalized event objects.
7007  * @static
7008  */
7009 Roo.EventManager = function(){
7010     var docReadyEvent, docReadyProcId, docReadyState = false;
7011     var resizeEvent, resizeTask, textEvent, textSize;
7012     var E = Roo.lib.Event;
7013     var D = Roo.lib.Dom;
7014
7015     
7016     
7017
7018     var fireDocReady = function(){
7019         if(!docReadyState){
7020             docReadyState = true;
7021             Roo.isReady = true;
7022             if(docReadyProcId){
7023                 clearInterval(docReadyProcId);
7024             }
7025             if(Roo.isGecko || Roo.isOpera) {
7026                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
7027             }
7028             if(Roo.isIE){
7029                 var defer = document.getElementById("ie-deferred-loader");
7030                 if(defer){
7031                     defer.onreadystatechange = null;
7032                     defer.parentNode.removeChild(defer);
7033                 }
7034             }
7035             if(docReadyEvent){
7036                 docReadyEvent.fire();
7037                 docReadyEvent.clearListeners();
7038             }
7039         }
7040     };
7041     
7042     var initDocReady = function(){
7043         docReadyEvent = new Roo.util.Event();
7044         if(Roo.isGecko || Roo.isOpera) {
7045             document.addEventListener("DOMContentLoaded", fireDocReady, false);
7046         }else if(Roo.isIE){
7047             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
7048             var defer = document.getElementById("ie-deferred-loader");
7049             defer.onreadystatechange = function(){
7050                 if(this.readyState == "complete"){
7051                     fireDocReady();
7052                 }
7053             };
7054         }else if(Roo.isSafari){ 
7055             docReadyProcId = setInterval(function(){
7056                 var rs = document.readyState;
7057                 if(rs == "complete") {
7058                     fireDocReady();     
7059                  }
7060             }, 10);
7061         }
7062         // no matter what, make sure it fires on load
7063         E.on(window, "load", fireDocReady);
7064     };
7065
7066     var createBuffered = function(h, o){
7067         var task = new Roo.util.DelayedTask(h);
7068         return function(e){
7069             // create new event object impl so new events don't wipe out properties
7070             e = new Roo.EventObjectImpl(e);
7071             task.delay(o.buffer, h, null, [e]);
7072         };
7073     };
7074
7075     var createSingle = function(h, el, ename, fn){
7076         return function(e){
7077             Roo.EventManager.removeListener(el, ename, fn);
7078             h(e);
7079         };
7080     };
7081
7082     var createDelayed = function(h, o){
7083         return function(e){
7084             // create new event object impl so new events don't wipe out properties
7085             e = new Roo.EventObjectImpl(e);
7086             setTimeout(function(){
7087                 h(e);
7088             }, o.delay || 10);
7089         };
7090     };
7091     var transitionEndVal = false;
7092     
7093     var transitionEnd = function()
7094     {
7095         if (transitionEndVal) {
7096             return transitionEndVal;
7097         }
7098         var el = document.createElement('div');
7099
7100         var transEndEventNames = {
7101             WebkitTransition : 'webkitTransitionEnd',
7102             MozTransition    : 'transitionend',
7103             OTransition      : 'oTransitionEnd otransitionend',
7104             transition       : 'transitionend'
7105         };
7106     
7107         for (var name in transEndEventNames) {
7108             if (el.style[name] !== undefined) {
7109                 transitionEndVal = transEndEventNames[name];
7110                 return  transitionEndVal ;
7111             }
7112         }
7113     }
7114     
7115   
7116
7117     var listen = function(element, ename, opt, fn, scope)
7118     {
7119         var o = (!opt || typeof opt == "boolean") ? {} : opt;
7120         fn = fn || o.fn; scope = scope || o.scope;
7121         var el = Roo.getDom(element);
7122         
7123         
7124         if(!el){
7125             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
7126         }
7127         
7128         if (ename == 'transitionend') {
7129             ename = transitionEnd();
7130         }
7131         var h = function(e){
7132             e = Roo.EventObject.setEvent(e);
7133             var t;
7134             if(o.delegate){
7135                 t = e.getTarget(o.delegate, el);
7136                 if(!t){
7137                     return;
7138                 }
7139             }else{
7140                 t = e.target;
7141             }
7142             if(o.stopEvent === true){
7143                 e.stopEvent();
7144             }
7145             if(o.preventDefault === true){
7146                e.preventDefault();
7147             }
7148             if(o.stopPropagation === true){
7149                 e.stopPropagation();
7150             }
7151
7152             if(o.normalized === false){
7153                 e = e.browserEvent;
7154             }
7155
7156             fn.call(scope || el, e, t, o);
7157         };
7158         if(o.delay){
7159             h = createDelayed(h, o);
7160         }
7161         if(o.single){
7162             h = createSingle(h, el, ename, fn);
7163         }
7164         if(o.buffer){
7165             h = createBuffered(h, o);
7166         }
7167         
7168         fn._handlers = fn._handlers || [];
7169         
7170         
7171         fn._handlers.push([Roo.id(el), ename, h]);
7172         
7173         
7174          
7175         E.on(el, ename, h); // this adds the actuall listener to the object..
7176         
7177         
7178         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
7179             el.addEventListener("DOMMouseScroll", h, false);
7180             E.on(window, 'unload', function(){
7181                 el.removeEventListener("DOMMouseScroll", h, false);
7182             });
7183         }
7184         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
7185             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
7186         }
7187         return h;
7188     };
7189
7190     var stopListening = function(el, ename, fn){
7191         var id = Roo.id(el), hds = fn._handlers, hd = fn;
7192         if(hds){
7193             for(var i = 0, len = hds.length; i < len; i++){
7194                 var h = hds[i];
7195                 if(h[0] == id && h[1] == ename){
7196                     hd = h[2];
7197                     hds.splice(i, 1);
7198                     break;
7199                 }
7200             }
7201         }
7202         E.un(el, ename, hd);
7203         el = Roo.getDom(el);
7204         if(ename == "mousewheel" && el.addEventListener){
7205             el.removeEventListener("DOMMouseScroll", hd, false);
7206         }
7207         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
7208             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
7209         }
7210     };
7211
7212     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
7213     
7214     var pub = {
7215         
7216         
7217         /** 
7218          * Fix for doc tools
7219          * @scope Roo.EventManager
7220          */
7221         
7222         
7223         /** 
7224          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
7225          * object with a Roo.EventObject
7226          * @param {Function} fn        The method the event invokes
7227          * @param {Object}   scope    An object that becomes the scope of the handler
7228          * @param {boolean}  override If true, the obj passed in becomes
7229          *                             the execution scope of the listener
7230          * @return {Function} The wrapped function
7231          * @deprecated
7232          */
7233         wrap : function(fn, scope, override){
7234             return function(e){
7235                 Roo.EventObject.setEvent(e);
7236                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
7237             };
7238         },
7239         
7240         /**
7241      * Appends an event handler to an element (shorthand for addListener)
7242      * @param {String/HTMLElement}   element        The html element or id to assign the
7243      * @param {String}   eventName The type of event to listen for
7244      * @param {Function} handler The method the event invokes
7245      * @param {Object}   scope (optional) The scope in which to execute the handler
7246      * function. The handler function's "this" context.
7247      * @param {Object}   options (optional) An object containing handler configuration
7248      * properties. This may contain any of the following properties:<ul>
7249      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
7250      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
7251      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
7252      * <li>preventDefault {Boolean} True to prevent the default action</li>
7253      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
7254      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
7255      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
7256      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
7257      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
7258      * by the specified number of milliseconds. If the event fires again within that time, the original
7259      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
7260      * </ul><br>
7261      * <p>
7262      * <b>Combining Options</b><br>
7263      * Using the options argument, it is possible to combine different types of listeners:<br>
7264      * <br>
7265      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
7266      * Code:<pre><code>
7267 el.on('click', this.onClick, this, {
7268     single: true,
7269     delay: 100,
7270     stopEvent : true,
7271     forumId: 4
7272 });</code></pre>
7273      * <p>
7274      * <b>Attaching multiple handlers in 1 call</b><br>
7275       * The method also allows for a single argument to be passed which is a config object containing properties
7276      * which specify multiple handlers.
7277      * <p>
7278      * Code:<pre><code>
7279 el.on({
7280     'click' : {
7281         fn: this.onClick
7282         scope: this,
7283         delay: 100
7284     },
7285     'mouseover' : {
7286         fn: this.onMouseOver
7287         scope: this
7288     },
7289     'mouseout' : {
7290         fn: this.onMouseOut
7291         scope: this
7292     }
7293 });</code></pre>
7294      * <p>
7295      * Or a shorthand syntax:<br>
7296      * Code:<pre><code>
7297 el.on({
7298     'click' : this.onClick,
7299     'mouseover' : this.onMouseOver,
7300     'mouseout' : this.onMouseOut
7301     scope: this
7302 });</code></pre>
7303      */
7304         addListener : function(element, eventName, fn, scope, options){
7305             if(typeof eventName == "object"){
7306                 var o = eventName;
7307                 for(var e in o){
7308                     if(propRe.test(e)){
7309                         continue;
7310                     }
7311                     if(typeof o[e] == "function"){
7312                         // shared options
7313                         listen(element, e, o, o[e], o.scope);
7314                     }else{
7315                         // individual options
7316                         listen(element, e, o[e]);
7317                     }
7318                 }
7319                 return;
7320             }
7321             return listen(element, eventName, options, fn, scope);
7322         },
7323         
7324         /**
7325          * Removes an event handler
7326          *
7327          * @param {String/HTMLElement}   element        The id or html element to remove the 
7328          *                             event from
7329          * @param {String}   eventName     The type of event
7330          * @param {Function} fn
7331          * @return {Boolean} True if a listener was actually removed
7332          */
7333         removeListener : function(element, eventName, fn){
7334             return stopListening(element, eventName, fn);
7335         },
7336         
7337         /**
7338          * Fires when the document is ready (before onload and before images are loaded). Can be 
7339          * accessed shorthanded Roo.onReady().
7340          * @param {Function} fn        The method the event invokes
7341          * @param {Object}   scope    An  object that becomes the scope of the handler
7342          * @param {boolean}  options
7343          */
7344         onDocumentReady : function(fn, scope, options){
7345             if(docReadyState){ // if it already fired
7346                 docReadyEvent.addListener(fn, scope, options);
7347                 docReadyEvent.fire();
7348                 docReadyEvent.clearListeners();
7349                 return;
7350             }
7351             if(!docReadyEvent){
7352                 initDocReady();
7353             }
7354             docReadyEvent.addListener(fn, scope, options);
7355         },
7356         
7357         /**
7358          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
7359          * @param {Function} fn        The method the event invokes
7360          * @param {Object}   scope    An object that becomes the scope of the handler
7361          * @param {boolean}  options
7362          */
7363         onWindowResize : function(fn, scope, options)
7364         {
7365             if(!resizeEvent){
7366                 resizeEvent = new Roo.util.Event();
7367                 resizeTask = new Roo.util.DelayedTask(function(){
7368                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
7369                 });
7370                 E.on(window, "resize", function()
7371                 {
7372                     if (Roo.isIE) {
7373                         resizeTask.delay(50);
7374                     } else {
7375                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
7376                     }
7377                 });
7378             }
7379             resizeEvent.addListener(fn, scope, options);
7380         },
7381
7382         /**
7383          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
7384          * @param {Function} fn        The method the event invokes
7385          * @param {Object}   scope    An object that becomes the scope of the handler
7386          * @param {boolean}  options
7387          */
7388         onTextResize : function(fn, scope, options){
7389             if(!textEvent){
7390                 textEvent = new Roo.util.Event();
7391                 var textEl = new Roo.Element(document.createElement('div'));
7392                 textEl.dom.className = 'x-text-resize';
7393                 textEl.dom.innerHTML = 'X';
7394                 textEl.appendTo(document.body);
7395                 textSize = textEl.dom.offsetHeight;
7396                 setInterval(function(){
7397                     if(textEl.dom.offsetHeight != textSize){
7398                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
7399                     }
7400                 }, this.textResizeInterval);
7401             }
7402             textEvent.addListener(fn, scope, options);
7403         },
7404
7405         /**
7406          * Removes the passed window resize listener.
7407          * @param {Function} fn        The method the event invokes
7408          * @param {Object}   scope    The scope of handler
7409          */
7410         removeResizeListener : function(fn, scope){
7411             if(resizeEvent){
7412                 resizeEvent.removeListener(fn, scope);
7413             }
7414         },
7415
7416         // private
7417         fireResize : function(){
7418             if(resizeEvent){
7419                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
7420             }   
7421         },
7422         /**
7423          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
7424          */
7425         ieDeferSrc : false,
7426         /**
7427          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
7428          */
7429         textResizeInterval : 50
7430     };
7431     
7432     /**
7433      * Fix for doc tools
7434      * @scopeAlias pub=Roo.EventManager
7435      */
7436     
7437      /**
7438      * Appends an event handler to an element (shorthand for addListener)
7439      * @param {String/HTMLElement}   element        The html element or id to assign the
7440      * @param {String}   eventName The type of event to listen for
7441      * @param {Function} handler The method the event invokes
7442      * @param {Object}   scope (optional) The scope in which to execute the handler
7443      * function. The handler function's "this" context.
7444      * @param {Object}   options (optional) An object containing handler configuration
7445      * properties. This may contain any of the following properties:<ul>
7446      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
7447      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
7448      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
7449      * <li>preventDefault {Boolean} True to prevent the default action</li>
7450      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
7451      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
7452      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
7453      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
7454      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
7455      * by the specified number of milliseconds. If the event fires again within that time, the original
7456      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
7457      * </ul><br>
7458      * <p>
7459      * <b>Combining Options</b><br>
7460      * Using the options argument, it is possible to combine different types of listeners:<br>
7461      * <br>
7462      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
7463      * Code:<pre><code>
7464 el.on('click', this.onClick, this, {
7465     single: true,
7466     delay: 100,
7467     stopEvent : true,
7468     forumId: 4
7469 });</code></pre>
7470      * <p>
7471      * <b>Attaching multiple handlers in 1 call</b><br>
7472       * The method also allows for a single argument to be passed which is a config object containing properties
7473      * which specify multiple handlers.
7474      * <p>
7475      * Code:<pre><code>
7476 el.on({
7477     'click' : {
7478         fn: this.onClick
7479         scope: this,
7480         delay: 100
7481     },
7482     'mouseover' : {
7483         fn: this.onMouseOver
7484         scope: this
7485     },
7486     'mouseout' : {
7487         fn: this.onMouseOut
7488         scope: this
7489     }
7490 });</code></pre>
7491      * <p>
7492      * Or a shorthand syntax:<br>
7493      * Code:<pre><code>
7494 el.on({
7495     'click' : this.onClick,
7496     'mouseover' : this.onMouseOver,
7497     'mouseout' : this.onMouseOut
7498     scope: this
7499 });</code></pre>
7500      */
7501     pub.on = pub.addListener;
7502     pub.un = pub.removeListener;
7503
7504     pub.stoppedMouseDownEvent = new Roo.util.Event();
7505     return pub;
7506 }();
7507 /**
7508   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
7509   * @param {Function} fn        The method the event invokes
7510   * @param {Object}   scope    An  object that becomes the scope of the handler
7511   * @param {boolean}  override If true, the obj passed in becomes
7512   *                             the execution scope of the listener
7513   * @member Roo
7514   * @method onReady
7515  */
7516 Roo.onReady = Roo.EventManager.onDocumentReady;
7517
7518 Roo.onReady(function(){
7519     var bd = Roo.get(document.body);
7520     if(!bd){ return; }
7521
7522     var cls = [
7523             Roo.isIE ? "roo-ie"
7524             : Roo.isIE11 ? "roo-ie11"
7525             : Roo.isEdge ? "roo-edge"
7526             : Roo.isGecko ? "roo-gecko"
7527             : Roo.isOpera ? "roo-opera"
7528             : Roo.isSafari ? "roo-safari" : ""];
7529
7530     if(Roo.isMac){
7531         cls.push("roo-mac");
7532     }
7533     if(Roo.isLinux){
7534         cls.push("roo-linux");
7535     }
7536     if(Roo.isIOS){
7537         cls.push("roo-ios");
7538     }
7539     if(Roo.isTouch){
7540         cls.push("roo-touch");
7541     }
7542     if(Roo.isBorderBox){
7543         cls.push('roo-border-box');
7544     }
7545     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
7546         var p = bd.dom.parentNode;
7547         if(p){
7548             p.className += ' roo-strict';
7549         }
7550     }
7551     bd.addClass(cls.join(' '));
7552 });
7553
7554 /**
7555  * @class Roo.EventObject
7556  * EventObject exposes the Yahoo! UI Event functionality directly on the object
7557  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
7558  * Example:
7559  * <pre><code>
7560  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
7561     e.preventDefault();
7562     var target = e.getTarget();
7563     ...
7564  }
7565  var myDiv = Roo.get("myDiv");
7566  myDiv.on("click", handleClick);
7567  //or
7568  Roo.EventManager.on("myDiv", 'click', handleClick);
7569  Roo.EventManager.addListener("myDiv", 'click', handleClick);
7570  </code></pre>
7571  * @static
7572  */
7573 Roo.EventObject = function(){
7574     
7575     var E = Roo.lib.Event;
7576     
7577     // safari keypress events for special keys return bad keycodes
7578     var safariKeys = {
7579         63234 : 37, // left
7580         63235 : 39, // right
7581         63232 : 38, // up
7582         63233 : 40, // down
7583         63276 : 33, // page up
7584         63277 : 34, // page down
7585         63272 : 46, // delete
7586         63273 : 36, // home
7587         63275 : 35  // end
7588     };
7589
7590     // normalize button clicks
7591     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
7592                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
7593
7594     Roo.EventObjectImpl = function(e){
7595         if(e){
7596             this.setEvent(e.browserEvent || e);
7597         }
7598     };
7599     Roo.EventObjectImpl.prototype = {
7600         /**
7601          * Used to fix doc tools.
7602          * @scope Roo.EventObject.prototype
7603          */
7604             
7605
7606         
7607         
7608         /** The normal browser event */
7609         browserEvent : null,
7610         /** The button pressed in a mouse event */
7611         button : -1,
7612         /** True if the shift key was down during the event */
7613         shiftKey : false,
7614         /** True if the control key was down during the event */
7615         ctrlKey : false,
7616         /** True if the alt key was down during the event */
7617         altKey : false,
7618
7619         /** Key constant 
7620         * @type Number */
7621         BACKSPACE : 8,
7622         /** Key constant 
7623         * @type Number */
7624         TAB : 9,
7625         /** Key constant 
7626         * @type Number */
7627         RETURN : 13,
7628         /** Key constant 
7629         * @type Number */
7630         ENTER : 13,
7631         /** Key constant 
7632         * @type Number */
7633         SHIFT : 16,
7634         /** Key constant 
7635         * @type Number */
7636         CONTROL : 17,
7637         /** Key constant 
7638         * @type Number */
7639         ESC : 27,
7640         /** Key constant 
7641         * @type Number */
7642         SPACE : 32,
7643         /** Key constant 
7644         * @type Number */
7645         PAGEUP : 33,
7646         /** Key constant 
7647         * @type Number */
7648         PAGEDOWN : 34,
7649         /** Key constant 
7650         * @type Number */
7651         END : 35,
7652         /** Key constant 
7653         * @type Number */
7654         HOME : 36,
7655         /** Key constant 
7656         * @type Number */
7657         LEFT : 37,
7658         /** Key constant 
7659         * @type Number */
7660         UP : 38,
7661         /** Key constant 
7662         * @type Number */
7663         RIGHT : 39,
7664         /** Key constant 
7665         * @type Number */
7666         DOWN : 40,
7667         /** Key constant 
7668         * @type Number */
7669         DELETE : 46,
7670         /** Key constant 
7671         * @type Number */
7672         F5 : 116,
7673
7674            /** @private */
7675         setEvent : function(e){
7676             if(e == this || (e && e.browserEvent)){ // already wrapped
7677                 return e;
7678             }
7679             this.browserEvent = e;
7680             if(e){
7681                 // normalize buttons
7682                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
7683                 if(e.type == 'click' && this.button == -1){
7684                     this.button = 0;
7685                 }
7686                 this.type = e.type;
7687                 this.shiftKey = e.shiftKey;
7688                 // mac metaKey behaves like ctrlKey
7689                 this.ctrlKey = e.ctrlKey || e.metaKey;
7690                 this.altKey = e.altKey;
7691                 // in getKey these will be normalized for the mac
7692                 this.keyCode = e.keyCode;
7693                 // keyup warnings on firefox.
7694                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
7695                 // cache the target for the delayed and or buffered events
7696                 this.target = E.getTarget(e);
7697                 // same for XY
7698                 this.xy = E.getXY(e);
7699             }else{
7700                 this.button = -1;
7701                 this.shiftKey = false;
7702                 this.ctrlKey = false;
7703                 this.altKey = false;
7704                 this.keyCode = 0;
7705                 this.charCode =0;
7706                 this.target = null;
7707                 this.xy = [0, 0];
7708             }
7709             return this;
7710         },
7711
7712         /**
7713          * Stop the event (preventDefault and stopPropagation)
7714          */
7715         stopEvent : function(){
7716             if(this.browserEvent){
7717                 if(this.browserEvent.type == 'mousedown'){
7718                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
7719                 }
7720                 E.stopEvent(this.browserEvent);
7721             }
7722         },
7723
7724         /**
7725          * Prevents the browsers default handling of the event.
7726          */
7727         preventDefault : function(){
7728             if(this.browserEvent){
7729                 E.preventDefault(this.browserEvent);
7730             }
7731         },
7732
7733         /** @private */
7734         isNavKeyPress : function(){
7735             var k = this.keyCode;
7736             k = Roo.isSafari ? (safariKeys[k] || k) : k;
7737             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
7738         },
7739
7740         isSpecialKey : function(){
7741             var k = this.keyCode;
7742             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
7743             (k == 16) || (k == 17) ||
7744             (k >= 18 && k <= 20) ||
7745             (k >= 33 && k <= 35) ||
7746             (k >= 36 && k <= 39) ||
7747             (k >= 44 && k <= 45);
7748         },
7749         /**
7750          * Cancels bubbling of the event.
7751          */
7752         stopPropagation : function(){
7753             if(this.browserEvent){
7754                 if(this.type == 'mousedown'){
7755                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
7756                 }
7757                 E.stopPropagation(this.browserEvent);
7758             }
7759         },
7760
7761         /**
7762          * Gets the key code for the event.
7763          * @return {Number}
7764          */
7765         getCharCode : function(){
7766             return this.charCode || this.keyCode;
7767         },
7768
7769         /**
7770          * Returns a normalized keyCode for the event.
7771          * @return {Number} The key code
7772          */
7773         getKey : function(){
7774             var k = this.keyCode || this.charCode;
7775             return Roo.isSafari ? (safariKeys[k] || k) : k;
7776         },
7777
7778         /**
7779          * Gets the x coordinate of the event.
7780          * @return {Number}
7781          */
7782         getPageX : function(){
7783             return this.xy[0];
7784         },
7785
7786         /**
7787          * Gets the y coordinate of the event.
7788          * @return {Number}
7789          */
7790         getPageY : function(){
7791             return this.xy[1];
7792         },
7793
7794         /**
7795          * Gets the time of the event.
7796          * @return {Number}
7797          */
7798         getTime : function(){
7799             if(this.browserEvent){
7800                 return E.getTime(this.browserEvent);
7801             }
7802             return null;
7803         },
7804
7805         /**
7806          * Gets the page coordinates of the event.
7807          * @return {Array} The xy values like [x, y]
7808          */
7809         getXY : function(){
7810             return this.xy;
7811         },
7812
7813         /**
7814          * Gets the target for the event.
7815          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
7816          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7817                 search as a number or element (defaults to 10 || document.body)
7818          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7819          * @return {HTMLelement}
7820          */
7821         getTarget : function(selector, maxDepth, returnEl){
7822             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
7823         },
7824         /**
7825          * Gets the related target.
7826          * @return {HTMLElement}
7827          */
7828         getRelatedTarget : function(){
7829             if(this.browserEvent){
7830                 return E.getRelatedTarget(this.browserEvent);
7831             }
7832             return null;
7833         },
7834
7835         /**
7836          * Normalizes mouse wheel delta across browsers
7837          * @return {Number} The delta
7838          */
7839         getWheelDelta : function(){
7840             var e = this.browserEvent;
7841             var delta = 0;
7842             if(e.wheelDelta){ /* IE/Opera. */
7843                 delta = e.wheelDelta/120;
7844             }else if(e.detail){ /* Mozilla case. */
7845                 delta = -e.detail/3;
7846             }
7847             return delta;
7848         },
7849
7850         /**
7851          * Returns true if the control, meta, shift or alt key was pressed during this event.
7852          * @return {Boolean}
7853          */
7854         hasModifier : function(){
7855             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
7856         },
7857
7858         /**
7859          * Returns true if the target of this event equals el or is a child of el
7860          * @param {String/HTMLElement/Element} el
7861          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
7862          * @return {Boolean}
7863          */
7864         within : function(el, related){
7865             var t = this[related ? "getRelatedTarget" : "getTarget"]();
7866             return t && Roo.fly(el).contains(t);
7867         },
7868
7869         getPoint : function(){
7870             return new Roo.lib.Point(this.xy[0], this.xy[1]);
7871         }
7872     };
7873
7874     return new Roo.EventObjectImpl();
7875 }();
7876             
7877     /*
7878  * Based on:
7879  * Ext JS Library 1.1.1
7880  * Copyright(c) 2006-2007, Ext JS, LLC.
7881  *
7882  * Originally Released Under LGPL - original licence link has changed is not relivant.
7883  *
7884  * Fork - LGPL
7885  * <script type="text/javascript">
7886  */
7887
7888  
7889 // was in Composite Element!??!?!
7890  
7891 (function(){
7892     var D = Roo.lib.Dom;
7893     var E = Roo.lib.Event;
7894     var A = Roo.lib.Anim;
7895
7896     // local style camelizing for speed
7897     var propCache = {};
7898     var camelRe = /(-[a-z])/gi;
7899     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
7900     var view = document.defaultView;
7901
7902 /**
7903  * @class Roo.Element
7904  * Represents an Element in the DOM.<br><br>
7905  * Usage:<br>
7906 <pre><code>
7907 var el = Roo.get("my-div");
7908
7909 // or with getEl
7910 var el = getEl("my-div");
7911
7912 // or with a DOM element
7913 var el = Roo.get(myDivElement);
7914 </code></pre>
7915  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
7916  * each call instead of constructing a new one.<br><br>
7917  * <b>Animations</b><br />
7918  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
7919  * should either be a boolean (true) or an object literal with animation options. The animation options are:
7920 <pre>
7921 Option    Default   Description
7922 --------- --------  ---------------------------------------------
7923 duration  .35       The duration of the animation in seconds
7924 easing    easeOut   The YUI easing method
7925 callback  none      A function to execute when the anim completes
7926 scope     this      The scope (this) of the callback function
7927 </pre>
7928 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
7929 * manipulate the animation. Here's an example:
7930 <pre><code>
7931 var el = Roo.get("my-div");
7932
7933 // no animation
7934 el.setWidth(100);
7935
7936 // default animation
7937 el.setWidth(100, true);
7938
7939 // animation with some options set
7940 el.setWidth(100, {
7941     duration: 1,
7942     callback: this.foo,
7943     scope: this
7944 });
7945
7946 // using the "anim" property to get the Anim object
7947 var opt = {
7948     duration: 1,
7949     callback: this.foo,
7950     scope: this
7951 };
7952 el.setWidth(100, opt);
7953 ...
7954 if(opt.anim.isAnimated()){
7955     opt.anim.stop();
7956 }
7957 </code></pre>
7958 * <b> Composite (Collections of) Elements</b><br />
7959  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
7960  * @constructor Create a new Element directly.
7961  * @param {String/HTMLElement} element
7962  * @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).
7963  */
7964     Roo.Element = function(element, forceNew)
7965     {
7966         var dom = typeof element == "string" ?
7967                 document.getElementById(element) : element;
7968         
7969         this.listeners = {};
7970         
7971         if(!dom){ // invalid id/element
7972             return null;
7973         }
7974         var id = dom.id;
7975         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7976             return Roo.Element.cache[id];
7977         }
7978
7979         /**
7980          * The DOM element
7981          * @type HTMLElement
7982          */
7983         this.dom = dom;
7984
7985         /**
7986          * The DOM element ID
7987          * @type String
7988          */
7989         this.id = id || Roo.id(dom);
7990         
7991         return this; // assumed for cctor?
7992     };
7993
7994     var El = Roo.Element;
7995
7996     El.prototype = {
7997         /**
7998          * The element's default display mode  (defaults to "") 
7999          * @type String
8000          */
8001         originalDisplay : "",
8002
8003         
8004         // note this is overridden in BS version..
8005         visibilityMode : 1, 
8006         /**
8007          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
8008          * @type String
8009          */
8010         defaultUnit : "px",
8011         
8012         /**
8013          * Sets the element's visibility mode. When setVisible() is called it
8014          * will use this to determine whether to set the visibility or the display property.
8015          * @param visMode Element.VISIBILITY or Element.DISPLAY
8016          * @return {Roo.Element} this
8017          */
8018         setVisibilityMode : function(visMode){
8019             this.visibilityMode = visMode;
8020             return this;
8021         },
8022         /**
8023          * Convenience method for setVisibilityMode(Element.DISPLAY)
8024          * @param {String} display (optional) What to set display to when visible
8025          * @return {Roo.Element} this
8026          */
8027         enableDisplayMode : function(display){
8028             this.setVisibilityMode(El.DISPLAY);
8029             if(typeof display != "undefined") { this.originalDisplay = display; }
8030             return this;
8031         },
8032
8033         /**
8034          * 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)
8035          * @param {String} selector The simple selector to test
8036          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8037                 search as a number or element (defaults to 10 || document.body)
8038          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
8039          * @return {HTMLElement} The matching DOM node (or null if no match was found)
8040          */
8041         findParent : function(simpleSelector, maxDepth, returnEl){
8042             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
8043             maxDepth = maxDepth || 50;
8044             if(typeof maxDepth != "number"){
8045                 stopEl = Roo.getDom(maxDepth);
8046                 maxDepth = 10;
8047             }
8048             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
8049                 if(dq.is(p, simpleSelector)){
8050                     return returnEl ? Roo.get(p) : p;
8051                 }
8052                 depth++;
8053                 p = p.parentNode;
8054             }
8055             return null;
8056         },
8057
8058
8059         /**
8060          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
8061          * @param {String} selector The simple selector to test
8062          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8063                 search as a number or element (defaults to 10 || document.body)
8064          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
8065          * @return {HTMLElement} The matching DOM node (or null if no match was found)
8066          */
8067         findParentNode : function(simpleSelector, maxDepth, returnEl){
8068             var p = Roo.fly(this.dom.parentNode, '_internal');
8069             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
8070         },
8071         
8072         /**
8073          * Looks at  the scrollable parent element
8074          */
8075         findScrollableParent : function()
8076         {
8077             var overflowRegex = /(auto|scroll)/;
8078             
8079             if(this.getStyle('position') === 'fixed'){
8080                 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
8081             }
8082             
8083             var excludeStaticParent = this.getStyle('position') === "absolute";
8084             
8085             for (var parent = this; (parent = Roo.get(parent.dom.parentNode));){
8086                 
8087                 if (excludeStaticParent && parent.getStyle('position') === "static") {
8088                     continue;
8089                 }
8090                 
8091                 if (overflowRegex.test(parent.getStyle('overflow') + parent.getStyle('overflow-x') + parent.getStyle('overflow-y'))){
8092                     return parent;
8093                 }
8094                 
8095                 if(parent.dom.nodeName.toLowerCase() == 'body'){
8096                     return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
8097                 }
8098             }
8099             
8100             return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
8101         },
8102
8103         /**
8104          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
8105          * This is a shortcut for findParentNode() that always returns an Roo.Element.
8106          * @param {String} selector The simple selector to test
8107          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8108                 search as a number or element (defaults to 10 || document.body)
8109          * @return {Roo.Element} The matching DOM node (or null if no match was found)
8110          */
8111         up : function(simpleSelector, maxDepth){
8112             return this.findParentNode(simpleSelector, maxDepth, true);
8113         },
8114
8115
8116
8117         /**
8118          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
8119          * @param {String} selector The simple selector to test
8120          * @return {Boolean} True if this element matches the selector, else false
8121          */
8122         is : function(simpleSelector){
8123             return Roo.DomQuery.is(this.dom, simpleSelector);
8124         },
8125
8126         /**
8127          * Perform animation on this element.
8128          * @param {Object} args The YUI animation control args
8129          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
8130          * @param {Function} onComplete (optional) Function to call when animation completes
8131          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
8132          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
8133          * @return {Roo.Element} this
8134          */
8135         animate : function(args, duration, onComplete, easing, animType){
8136             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
8137             return this;
8138         },
8139
8140         /*
8141          * @private Internal animation call
8142          */
8143         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
8144             animType = animType || 'run';
8145             opt = opt || {};
8146             var anim = Roo.lib.Anim[animType](
8147                 this.dom, args,
8148                 (opt.duration || defaultDur) || .35,
8149                 (opt.easing || defaultEase) || 'easeOut',
8150                 function(){
8151                     Roo.callback(cb, this);
8152                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
8153                 },
8154                 this
8155             );
8156             opt.anim = anim;
8157             return anim;
8158         },
8159
8160         // private legacy anim prep
8161         preanim : function(a, i){
8162             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
8163         },
8164
8165         /**
8166          * Removes worthless text nodes
8167          * @param {Boolean} forceReclean (optional) By default the element
8168          * keeps track if it has been cleaned already so
8169          * you can call this over and over. However, if you update the element and
8170          * need to force a reclean, you can pass true.
8171          */
8172         clean : function(forceReclean){
8173             if(this.isCleaned && forceReclean !== true){
8174                 return this;
8175             }
8176             var ns = /\S/;
8177             var d = this.dom, n = d.firstChild, ni = -1;
8178             while(n){
8179                 var nx = n.nextSibling;
8180                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
8181                     d.removeChild(n);
8182                 }else{
8183                     n.nodeIndex = ++ni;
8184                 }
8185                 n = nx;
8186             }
8187             this.isCleaned = true;
8188             return this;
8189         },
8190
8191         // private
8192         calcOffsetsTo : function(el){
8193             el = Roo.get(el);
8194             var d = el.dom;
8195             var restorePos = false;
8196             if(el.getStyle('position') == 'static'){
8197                 el.position('relative');
8198                 restorePos = true;
8199             }
8200             var x = 0, y =0;
8201             var op = this.dom;
8202             while(op && op != d && op.tagName != 'HTML'){
8203                 x+= op.offsetLeft;
8204                 y+= op.offsetTop;
8205                 op = op.offsetParent;
8206             }
8207             if(restorePos){
8208                 el.position('static');
8209             }
8210             return [x, y];
8211         },
8212
8213         /**
8214          * Scrolls this element into view within the passed container.
8215          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
8216          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
8217          * @return {Roo.Element} this
8218          */
8219         scrollIntoView : function(container, hscroll){
8220             var c = Roo.getDom(container) || document.body;
8221             var el = this.dom;
8222
8223             var o = this.calcOffsetsTo(c),
8224                 l = o[0],
8225                 t = o[1],
8226                 b = t+el.offsetHeight,
8227                 r = l+el.offsetWidth;
8228
8229             var ch = c.clientHeight;
8230             var ct = parseInt(c.scrollTop, 10);
8231             var cl = parseInt(c.scrollLeft, 10);
8232             var cb = ct + ch;
8233             var cr = cl + c.clientWidth;
8234
8235             if(t < ct){
8236                 c.scrollTop = t;
8237             }else if(b > cb){
8238                 c.scrollTop = b-ch;
8239             }
8240
8241             if(hscroll !== false){
8242                 if(l < cl){
8243                     c.scrollLeft = l;
8244                 }else if(r > cr){
8245                     c.scrollLeft = r-c.clientWidth;
8246                 }
8247             }
8248             return this;
8249         },
8250
8251         // private
8252         scrollChildIntoView : function(child, hscroll){
8253             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
8254         },
8255
8256         /**
8257          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
8258          * the new height may not be available immediately.
8259          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
8260          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
8261          * @param {Function} onComplete (optional) Function to call when animation completes
8262          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
8263          * @return {Roo.Element} this
8264          */
8265         autoHeight : function(animate, duration, onComplete, easing){
8266             var oldHeight = this.getHeight();
8267             this.clip();
8268             this.setHeight(1); // force clipping
8269             setTimeout(function(){
8270                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
8271                 if(!animate){
8272                     this.setHeight(height);
8273                     this.unclip();
8274                     if(typeof onComplete == "function"){
8275                         onComplete();
8276                     }
8277                 }else{
8278                     this.setHeight(oldHeight); // restore original height
8279                     this.setHeight(height, animate, duration, function(){
8280                         this.unclip();
8281                         if(typeof onComplete == "function") { onComplete(); }
8282                     }.createDelegate(this), easing);
8283                 }
8284             }.createDelegate(this), 0);
8285             return this;
8286         },
8287
8288         /**
8289          * Returns true if this element is an ancestor of the passed element
8290          * @param {HTMLElement/String} el The element to check
8291          * @return {Boolean} True if this element is an ancestor of el, else false
8292          */
8293         contains : function(el){
8294             if(!el){return false;}
8295             return D.isAncestor(this.dom, el.dom ? el.dom : el);
8296         },
8297
8298         /**
8299          * Checks whether the element is currently visible using both visibility and display properties.
8300          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
8301          * @return {Boolean} True if the element is currently visible, else false
8302          */
8303         isVisible : function(deep) {
8304             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
8305             if(deep !== true || !vis){
8306                 return vis;
8307             }
8308             var p = this.dom.parentNode;
8309             while(p && p.tagName.toLowerCase() != "body"){
8310                 if(!Roo.fly(p, '_isVisible').isVisible()){
8311                     return false;
8312                 }
8313                 p = p.parentNode;
8314             }
8315             return true;
8316         },
8317
8318         /**
8319          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
8320          * @param {String} selector The CSS selector
8321          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
8322          * @return {CompositeElement/CompositeElementLite} The composite element
8323          */
8324         select : function(selector, unique){
8325             return El.select(selector, unique, this.dom);
8326         },
8327
8328         /**
8329          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
8330          * @param {String} selector The CSS selector
8331          * @return {Array} An array of the matched nodes
8332          */
8333         query : function(selector, unique){
8334             return Roo.DomQuery.select(selector, this.dom);
8335         },
8336
8337         /**
8338          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
8339          * @param {String} selector The CSS selector
8340          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
8341          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
8342          */
8343         child : function(selector, returnDom){
8344             var n = Roo.DomQuery.selectNode(selector, this.dom);
8345             return returnDom ? n : Roo.get(n);
8346         },
8347
8348         /**
8349          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
8350          * @param {String} selector The CSS selector
8351          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
8352          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
8353          */
8354         down : function(selector, returnDom){
8355             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
8356             return returnDom ? n : Roo.get(n);
8357         },
8358
8359         /**
8360          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
8361          * @param {String} group The group the DD object is member of
8362          * @param {Object} config The DD config object
8363          * @param {Object} overrides An object containing methods to override/implement on the DD object
8364          * @return {Roo.dd.DD} The DD object
8365          */
8366         initDD : function(group, config, overrides){
8367             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
8368             return Roo.apply(dd, overrides);
8369         },
8370
8371         /**
8372          * Initializes a {@link Roo.dd.DDProxy} object for this element.
8373          * @param {String} group The group the DDProxy object is member of
8374          * @param {Object} config The DDProxy config object
8375          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
8376          * @return {Roo.dd.DDProxy} The DDProxy object
8377          */
8378         initDDProxy : function(group, config, overrides){
8379             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
8380             return Roo.apply(dd, overrides);
8381         },
8382
8383         /**
8384          * Initializes a {@link Roo.dd.DDTarget} object for this element.
8385          * @param {String} group The group the DDTarget object is member of
8386          * @param {Object} config The DDTarget config object
8387          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
8388          * @return {Roo.dd.DDTarget} The DDTarget object
8389          */
8390         initDDTarget : function(group, config, overrides){
8391             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
8392             return Roo.apply(dd, overrides);
8393         },
8394
8395         /**
8396          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
8397          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
8398          * @param {Boolean} visible Whether the element is visible
8399          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8400          * @return {Roo.Element} this
8401          */
8402          setVisible : function(visible, animate){
8403             if(!animate || !A){
8404                 if(this.visibilityMode == El.DISPLAY){
8405                     this.setDisplayed(visible);
8406                 }else{
8407                     this.fixDisplay();
8408                     this.dom.style.visibility = visible ? "visible" : "hidden";
8409                 }
8410             }else{
8411                 // closure for composites
8412                 var dom = this.dom;
8413                 var visMode = this.visibilityMode;
8414                 if(visible){
8415                     this.setOpacity(.01);
8416                     this.setVisible(true);
8417                 }
8418                 this.anim({opacity: { to: (visible?1:0) }},
8419                       this.preanim(arguments, 1),
8420                       null, .35, 'easeIn', function(){
8421                          if(!visible){
8422                              if(visMode == El.DISPLAY){
8423                                  dom.style.display = "none";
8424                              }else{
8425                                  dom.style.visibility = "hidden";
8426                              }
8427                              Roo.get(dom).setOpacity(1);
8428                          }
8429                      });
8430             }
8431             return this;
8432         },
8433
8434         /**
8435          * Returns true if display is not "none"
8436          * @return {Boolean}
8437          */
8438         isDisplayed : function() {
8439             return this.getStyle("display") != "none";
8440         },
8441
8442         /**
8443          * Toggles the element's visibility or display, depending on visibility mode.
8444          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8445          * @return {Roo.Element} this
8446          */
8447         toggle : function(animate){
8448             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
8449             return this;
8450         },
8451
8452         /**
8453          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
8454          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
8455          * @return {Roo.Element} this
8456          */
8457         setDisplayed : function(value) {
8458             if(typeof value == "boolean"){
8459                value = value ? this.originalDisplay : "none";
8460             }
8461             this.setStyle("display", value);
8462             return this;
8463         },
8464
8465         /**
8466          * Tries to focus the element. Any exceptions are caught and ignored.
8467          * @return {Roo.Element} this
8468          */
8469         focus : function() {
8470             try{
8471                 this.dom.focus();
8472             }catch(e){}
8473             return this;
8474         },
8475
8476         /**
8477          * Tries to blur the element. Any exceptions are caught and ignored.
8478          * @return {Roo.Element} this
8479          */
8480         blur : function() {
8481             try{
8482                 this.dom.blur();
8483             }catch(e){}
8484             return this;
8485         },
8486
8487         /**
8488          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
8489          * @param {String/Array} className The CSS class to add, or an array of classes
8490          * @return {Roo.Element} this
8491          */
8492         addClass : function(className){
8493             if(className instanceof Array){
8494                 for(var i = 0, len = className.length; i < len; i++) {
8495                     this.addClass(className[i]);
8496                 }
8497             }else{
8498                 if(className && !this.hasClass(className)){
8499                     if (this.dom instanceof SVGElement) {
8500                         this.dom.className.baseVal =this.dom.className.baseVal  + " " + className;
8501                     } else {
8502                         this.dom.className = this.dom.className + " " + className;
8503                     }
8504                 }
8505             }
8506             return this;
8507         },
8508
8509         /**
8510          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
8511          * @param {String/Array} className The CSS class to add, or an array of classes
8512          * @return {Roo.Element} this
8513          */
8514         radioClass : function(className){
8515             var siblings = this.dom.parentNode.childNodes;
8516             for(var i = 0; i < siblings.length; i++) {
8517                 var s = siblings[i];
8518                 if(s.nodeType == 1){
8519                     Roo.get(s).removeClass(className);
8520                 }
8521             }
8522             this.addClass(className);
8523             return this;
8524         },
8525
8526         /**
8527          * Removes one or more CSS classes from the element.
8528          * @param {String/Array} className The CSS class to remove, or an array of classes
8529          * @return {Roo.Element} this
8530          */
8531         removeClass : function(className){
8532             
8533             var cn = this.dom instanceof SVGElement ? this.dom.className.baseVal : this.dom.className;
8534             if(!className || !cn){
8535                 return this;
8536             }
8537             if(className instanceof Array){
8538                 for(var i = 0, len = className.length; i < len; i++) {
8539                     this.removeClass(className[i]);
8540                 }
8541             }else{
8542                 if(this.hasClass(className)){
8543                     var re = this.classReCache[className];
8544                     if (!re) {
8545                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
8546                        this.classReCache[className] = re;
8547                     }
8548                     if (this.dom instanceof SVGElement) {
8549                         this.dom.className.baseVal = cn.replace(re, " ");
8550                     } else {
8551                         this.dom.className = cn.replace(re, " ");
8552                     }
8553                 }
8554             }
8555             return this;
8556         },
8557
8558         // private
8559         classReCache: {},
8560
8561         /**
8562          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
8563          * @param {String} className The CSS class to toggle
8564          * @return {Roo.Element} this
8565          */
8566         toggleClass : function(className){
8567             if(this.hasClass(className)){
8568                 this.removeClass(className);
8569             }else{
8570                 this.addClass(className);
8571             }
8572             return this;
8573         },
8574
8575         /**
8576          * Checks if the specified CSS class exists on this element's DOM node.
8577          * @param {String} className The CSS class to check for
8578          * @return {Boolean} True if the class exists, else false
8579          */
8580         hasClass : function(className){
8581             if (this.dom instanceof SVGElement) {
8582                 return className && (' '+this.dom.className.baseVal +' ').indexOf(' '+className+' ') != -1; 
8583             } 
8584             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
8585         },
8586
8587         /**
8588          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
8589          * @param {String} oldClassName The CSS class to replace
8590          * @param {String} newClassName The replacement CSS class
8591          * @return {Roo.Element} this
8592          */
8593         replaceClass : function(oldClassName, newClassName){
8594             this.removeClass(oldClassName);
8595             this.addClass(newClassName);
8596             return this;
8597         },
8598
8599         /**
8600          * Returns an object with properties matching the styles requested.
8601          * For example, el.getStyles('color', 'font-size', 'width') might return
8602          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
8603          * @param {String} style1 A style name
8604          * @param {String} style2 A style name
8605          * @param {String} etc.
8606          * @return {Object} The style object
8607          */
8608         getStyles : function(){
8609             var a = arguments, len = a.length, r = {};
8610             for(var i = 0; i < len; i++){
8611                 r[a[i]] = this.getStyle(a[i]);
8612             }
8613             return r;
8614         },
8615
8616         /**
8617          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
8618          * @param {String} property The style property whose value is returned.
8619          * @return {String} The current value of the style property for this element.
8620          */
8621         getStyle : function(){
8622             return view && view.getComputedStyle ?
8623                 function(prop){
8624                     var el = this.dom, v, cs, camel;
8625                     if(prop == 'float'){
8626                         prop = "cssFloat";
8627                     }
8628                     if(el.style && (v = el.style[prop])){
8629                         return v;
8630                     }
8631                     if(cs = view.getComputedStyle(el, "")){
8632                         if(!(camel = propCache[prop])){
8633                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
8634                         }
8635                         return cs[camel];
8636                     }
8637                     return null;
8638                 } :
8639                 function(prop){
8640                     var el = this.dom, v, cs, camel;
8641                     if(prop == 'opacity'){
8642                         if(typeof el.style.filter == 'string'){
8643                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
8644                             if(m){
8645                                 var fv = parseFloat(m[1]);
8646                                 if(!isNaN(fv)){
8647                                     return fv ? fv / 100 : 0;
8648                                 }
8649                             }
8650                         }
8651                         return 1;
8652                     }else if(prop == 'float'){
8653                         prop = "styleFloat";
8654                     }
8655                     if(!(camel = propCache[prop])){
8656                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
8657                     }
8658                     if(v = el.style[camel]){
8659                         return v;
8660                     }
8661                     if(cs = el.currentStyle){
8662                         return cs[camel];
8663                     }
8664                     return null;
8665                 };
8666         }(),
8667
8668         /**
8669          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
8670          * @param {String/Object} property The style property to be set, or an object of multiple styles.
8671          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
8672          * @return {Roo.Element} this
8673          */
8674         setStyle : function(prop, value){
8675             if(typeof prop == "string"){
8676                 
8677                 if (prop == 'float') {
8678                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
8679                     return this;
8680                 }
8681                 
8682                 var camel;
8683                 if(!(camel = propCache[prop])){
8684                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
8685                 }
8686                 
8687                 if(camel == 'opacity') {
8688                     this.setOpacity(value);
8689                 }else{
8690                     this.dom.style[camel] = value;
8691                 }
8692             }else{
8693                 for(var style in prop){
8694                     if(typeof prop[style] != "function"){
8695                        this.setStyle(style, prop[style]);
8696                     }
8697                 }
8698             }
8699             return this;
8700         },
8701
8702         /**
8703          * More flexible version of {@link #setStyle} for setting style properties.
8704          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
8705          * a function which returns such a specification.
8706          * @return {Roo.Element} this
8707          */
8708         applyStyles : function(style){
8709             Roo.DomHelper.applyStyles(this.dom, style);
8710             return this;
8711         },
8712
8713         /**
8714           * 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).
8715           * @return {Number} The X position of the element
8716           */
8717         getX : function(){
8718             return D.getX(this.dom);
8719         },
8720
8721         /**
8722           * 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).
8723           * @return {Number} The Y position of the element
8724           */
8725         getY : function(){
8726             return D.getY(this.dom);
8727         },
8728
8729         /**
8730           * 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).
8731           * @return {Array} The XY position of the element
8732           */
8733         getXY : function(){
8734             return D.getXY(this.dom);
8735         },
8736
8737         /**
8738          * 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).
8739          * @param {Number} The X position of the element
8740          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8741          * @return {Roo.Element} this
8742          */
8743         setX : function(x, animate){
8744             if(!animate || !A){
8745                 D.setX(this.dom, x);
8746             }else{
8747                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
8748             }
8749             return this;
8750         },
8751
8752         /**
8753          * 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).
8754          * @param {Number} The Y position of the element
8755          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8756          * @return {Roo.Element} this
8757          */
8758         setY : function(y, animate){
8759             if(!animate || !A){
8760                 D.setY(this.dom, y);
8761             }else{
8762                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
8763             }
8764             return this;
8765         },
8766
8767         /**
8768          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
8769          * @param {String} left The left CSS property value
8770          * @return {Roo.Element} this
8771          */
8772         setLeft : function(left){
8773             this.setStyle("left", this.addUnits(left));
8774             return this;
8775         },
8776
8777         /**
8778          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
8779          * @param {String} top The top CSS property value
8780          * @return {Roo.Element} this
8781          */
8782         setTop : function(top){
8783             this.setStyle("top", this.addUnits(top));
8784             return this;
8785         },
8786
8787         /**
8788          * Sets the element's CSS right style.
8789          * @param {String} right The right CSS property value
8790          * @return {Roo.Element} this
8791          */
8792         setRight : function(right){
8793             this.setStyle("right", this.addUnits(right));
8794             return this;
8795         },
8796
8797         /**
8798          * Sets the element's CSS bottom style.
8799          * @param {String} bottom The bottom CSS property value
8800          * @return {Roo.Element} this
8801          */
8802         setBottom : function(bottom){
8803             this.setStyle("bottom", this.addUnits(bottom));
8804             return this;
8805         },
8806
8807         /**
8808          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
8809          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
8810          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
8811          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8812          * @return {Roo.Element} this
8813          */
8814         setXY : function(pos, animate){
8815             if(!animate || !A){
8816                 D.setXY(this.dom, pos);
8817             }else{
8818                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
8819             }
8820             return this;
8821         },
8822
8823         /**
8824          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
8825          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
8826          * @param {Number} x X value for new position (coordinates are page-based)
8827          * @param {Number} y Y value for new position (coordinates are page-based)
8828          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8829          * @return {Roo.Element} this
8830          */
8831         setLocation : function(x, y, animate){
8832             this.setXY([x, y], this.preanim(arguments, 2));
8833             return this;
8834         },
8835
8836         /**
8837          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
8838          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
8839          * @param {Number} x X value for new position (coordinates are page-based)
8840          * @param {Number} y Y value for new position (coordinates are page-based)
8841          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8842          * @return {Roo.Element} this
8843          */
8844         moveTo : function(x, y, animate){
8845             this.setXY([x, y], this.preanim(arguments, 2));
8846             return this;
8847         },
8848
8849         /**
8850          * Returns the region of the given element.
8851          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
8852          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
8853          */
8854         getRegion : function(){
8855             return D.getRegion(this.dom);
8856         },
8857
8858         /**
8859          * Returns the offset height of the element
8860          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
8861          * @return {Number} The element's height
8862          */
8863         getHeight : function(contentHeight){
8864             var h = this.dom.offsetHeight || 0;
8865             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
8866         },
8867
8868         /**
8869          * Returns the offset width of the element
8870          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
8871          * @return {Number} The element's width
8872          */
8873         getWidth : function(contentWidth){
8874             var w = this.dom.offsetWidth || 0;
8875             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
8876         },
8877
8878         /**
8879          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
8880          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
8881          * if a height has not been set using CSS.
8882          * @return {Number}
8883          */
8884         getComputedHeight : function(){
8885             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
8886             if(!h){
8887                 h = parseInt(this.getStyle('height'), 10) || 0;
8888                 if(!this.isBorderBox()){
8889                     h += this.getFrameWidth('tb');
8890                 }
8891             }
8892             return h;
8893         },
8894
8895         /**
8896          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
8897          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
8898          * if a width has not been set using CSS.
8899          * @return {Number}
8900          */
8901         getComputedWidth : function(){
8902             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
8903             if(!w){
8904                 w = parseInt(this.getStyle('width'), 10) || 0;
8905                 if(!this.isBorderBox()){
8906                     w += this.getFrameWidth('lr');
8907                 }
8908             }
8909             return w;
8910         },
8911
8912         /**
8913          * Returns the size of the element.
8914          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
8915          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
8916          */
8917         getSize : function(contentSize){
8918             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
8919         },
8920
8921         /**
8922          * Returns the width and height of the viewport.
8923          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
8924          */
8925         getViewSize : function(){
8926             var d = this.dom, doc = document, aw = 0, ah = 0;
8927             if(d == doc || d == doc.body){
8928                 return {width : D.getViewWidth(), height: D.getViewHeight()};
8929             }else{
8930                 return {
8931                     width : d.clientWidth,
8932                     height: d.clientHeight
8933                 };
8934             }
8935         },
8936
8937         /**
8938          * Returns the value of the "value" attribute
8939          * @param {Boolean} asNumber true to parse the value as a number
8940          * @return {String/Number}
8941          */
8942         getValue : function(asNumber){
8943             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
8944         },
8945
8946         // private
8947         adjustWidth : function(width){
8948             if(typeof width == "number"){
8949                 if(this.autoBoxAdjust && !this.isBorderBox()){
8950                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8951                 }
8952                 if(width < 0){
8953                     width = 0;
8954                 }
8955             }
8956             return width;
8957         },
8958
8959         // private
8960         adjustHeight : function(height){
8961             if(typeof height == "number"){
8962                if(this.autoBoxAdjust && !this.isBorderBox()){
8963                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8964                }
8965                if(height < 0){
8966                    height = 0;
8967                }
8968             }
8969             return height;
8970         },
8971
8972         /**
8973          * Set the width of the element
8974          * @param {Number} width The new width
8975          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8976          * @return {Roo.Element} this
8977          */
8978         setWidth : function(width, animate){
8979             width = this.adjustWidth(width);
8980             if(!animate || !A){
8981                 this.dom.style.width = this.addUnits(width);
8982             }else{
8983                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
8984             }
8985             return this;
8986         },
8987
8988         /**
8989          * Set the height of the element
8990          * @param {Number} height The new height
8991          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8992          * @return {Roo.Element} this
8993          */
8994          setHeight : function(height, animate){
8995             height = this.adjustHeight(height);
8996             if(!animate || !A){
8997                 this.dom.style.height = this.addUnits(height);
8998             }else{
8999                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
9000             }
9001             return this;
9002         },
9003
9004         /**
9005          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
9006          * @param {Number} width The new width
9007          * @param {Number} height The new height
9008          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9009          * @return {Roo.Element} this
9010          */
9011          setSize : function(width, height, animate){
9012             if(typeof width == "object"){ // in case of object from getSize()
9013                 height = width.height; width = width.width;
9014             }
9015             width = this.adjustWidth(width); height = this.adjustHeight(height);
9016             if(!animate || !A){
9017                 this.dom.style.width = this.addUnits(width);
9018                 this.dom.style.height = this.addUnits(height);
9019             }else{
9020                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
9021             }
9022             return this;
9023         },
9024
9025         /**
9026          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
9027          * @param {Number} x X value for new position (coordinates are page-based)
9028          * @param {Number} y Y value for new position (coordinates are page-based)
9029          * @param {Number} width The new width
9030          * @param {Number} height The new height
9031          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9032          * @return {Roo.Element} this
9033          */
9034         setBounds : function(x, y, width, height, animate){
9035             if(!animate || !A){
9036                 this.setSize(width, height);
9037                 this.setLocation(x, y);
9038             }else{
9039                 width = this.adjustWidth(width); height = this.adjustHeight(height);
9040                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
9041                               this.preanim(arguments, 4), 'motion');
9042             }
9043             return this;
9044         },
9045
9046         /**
9047          * 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.
9048          * @param {Roo.lib.Region} region The region to fill
9049          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9050          * @return {Roo.Element} this
9051          */
9052         setRegion : function(region, animate){
9053             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
9054             return this;
9055         },
9056
9057         /**
9058          * Appends an event handler
9059          *
9060          * @param {String}   eventName     The type of event to append
9061          * @param {Function} fn        The method the event invokes
9062          * @param {Object} scope       (optional) The scope (this object) of the fn
9063          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9064          */
9065         addListener : function(eventName, fn, scope, options)
9066         {
9067             if (eventName == 'dblclick') { // doublclick (touchstart) - faked on touch.
9068                 this.addListener('touchstart', this.onTapHandler, this);
9069             }
9070             
9071             // we need to handle a special case where dom element is a svg element.
9072             // in this case we do not actua
9073             if (!this.dom) {
9074                 return;
9075             }
9076             
9077             if (this.dom instanceof SVGElement && !(this.dom instanceof SVGSVGElement)) {
9078                 if (typeof(this.listeners[eventName]) == 'undefined') {
9079                     this.listeners[eventName] =  new Roo.util.Event(this, eventName);
9080                 }
9081                 this.listeners[eventName].addListener(fn, scope, options);
9082                 return;
9083             }
9084             
9085                 
9086             Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
9087             
9088             
9089         },
9090         tapedTwice : false,
9091         onTapHandler : function(event)
9092         {
9093             if(!this.tapedTwice) {
9094                 this.tapedTwice = true;
9095                 var s = this;
9096                 setTimeout( function() {
9097                     s.tapedTwice = false;
9098                 }, 300 );
9099                 return;
9100             }
9101             event.preventDefault();
9102             var revent = new MouseEvent('dblclick',  {
9103                 view: window,
9104                 bubbles: true,
9105                 cancelable: true
9106             });
9107              
9108             this.dom.dispatchEvent(revent);
9109             //action on double tap goes below
9110              
9111         }, 
9112  
9113         /**
9114          * Removes an event handler from this element
9115          * @param {String} eventName the type of event to remove
9116          * @param {Function} fn the method the event invokes
9117          * @param {Function} scope (needed for svg fake listeners)
9118          * @return {Roo.Element} this
9119          */
9120         removeListener : function(eventName, fn, scope){
9121             Roo.EventManager.removeListener(this.dom,  eventName, fn);
9122             if (typeof(this.listeners) == 'undefined'  || typeof(this.listeners[eventName]) == 'undefined') {
9123                 return this;
9124             }
9125             this.listeners[eventName].removeListener(fn, scope);
9126             return this;
9127         },
9128
9129         /**
9130          * Removes all previous added listeners from this element
9131          * @return {Roo.Element} this
9132          */
9133         removeAllListeners : function(){
9134             E.purgeElement(this.dom);
9135             this.listeners = {};
9136             return this;
9137         },
9138
9139         relayEvent : function(eventName, observable){
9140             this.on(eventName, function(e){
9141                 observable.fireEvent(eventName, e);
9142             });
9143         },
9144
9145         
9146         /**
9147          * Set the opacity of the element
9148          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
9149          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9150          * @return {Roo.Element} this
9151          */
9152          setOpacity : function(opacity, animate){
9153             if(!animate || !A){
9154                 var s = this.dom.style;
9155                 if(Roo.isIE){
9156                     s.zoom = 1;
9157                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
9158                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
9159                 }else{
9160                     s.opacity = opacity;
9161                 }
9162             }else{
9163                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
9164             }
9165             return this;
9166         },
9167
9168         /**
9169          * Gets the left X coordinate
9170          * @param {Boolean} local True to get the local css position instead of page coordinate
9171          * @return {Number}
9172          */
9173         getLeft : function(local){
9174             if(!local){
9175                 return this.getX();
9176             }else{
9177                 return parseInt(this.getStyle("left"), 10) || 0;
9178             }
9179         },
9180
9181         /**
9182          * Gets the right X coordinate of the element (element X position + element width)
9183          * @param {Boolean} local True to get the local css position instead of page coordinate
9184          * @return {Number}
9185          */
9186         getRight : function(local){
9187             if(!local){
9188                 return this.getX() + this.getWidth();
9189             }else{
9190                 return (this.getLeft(true) + this.getWidth()) || 0;
9191             }
9192         },
9193
9194         /**
9195          * Gets the top Y coordinate
9196          * @param {Boolean} local True to get the local css position instead of page coordinate
9197          * @return {Number}
9198          */
9199         getTop : function(local) {
9200             if(!local){
9201                 return this.getY();
9202             }else{
9203                 return parseInt(this.getStyle("top"), 10) || 0;
9204             }
9205         },
9206
9207         /**
9208          * Gets the bottom Y coordinate of the element (element Y position + element height)
9209          * @param {Boolean} local True to get the local css position instead of page coordinate
9210          * @return {Number}
9211          */
9212         getBottom : function(local){
9213             if(!local){
9214                 return this.getY() + this.getHeight();
9215             }else{
9216                 return (this.getTop(true) + this.getHeight()) || 0;
9217             }
9218         },
9219
9220         /**
9221         * Initializes positioning on this element. If a desired position is not passed, it will make the
9222         * the element positioned relative IF it is not already positioned.
9223         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
9224         * @param {Number} zIndex (optional) The zIndex to apply
9225         * @param {Number} x (optional) Set the page X position
9226         * @param {Number} y (optional) Set the page Y position
9227         */
9228         position : function(pos, zIndex, x, y){
9229             if(!pos){
9230                if(this.getStyle('position') == 'static'){
9231                    this.setStyle('position', 'relative');
9232                }
9233             }else{
9234                 this.setStyle("position", pos);
9235             }
9236             if(zIndex){
9237                 this.setStyle("z-index", zIndex);
9238             }
9239             if(x !== undefined && y !== undefined){
9240                 this.setXY([x, y]);
9241             }else if(x !== undefined){
9242                 this.setX(x);
9243             }else if(y !== undefined){
9244                 this.setY(y);
9245             }
9246         },
9247
9248         /**
9249         * Clear positioning back to the default when the document was loaded
9250         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
9251         * @return {Roo.Element} this
9252          */
9253         clearPositioning : function(value){
9254             value = value ||'';
9255             this.setStyle({
9256                 "left": value,
9257                 "right": value,
9258                 "top": value,
9259                 "bottom": value,
9260                 "z-index": "",
9261                 "position" : "static"
9262             });
9263             return this;
9264         },
9265
9266         /**
9267         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
9268         * snapshot before performing an update and then restoring the element.
9269         * @return {Object}
9270         */
9271         getPositioning : function(){
9272             var l = this.getStyle("left");
9273             var t = this.getStyle("top");
9274             return {
9275                 "position" : this.getStyle("position"),
9276                 "left" : l,
9277                 "right" : l ? "" : this.getStyle("right"),
9278                 "top" : t,
9279                 "bottom" : t ? "" : this.getStyle("bottom"),
9280                 "z-index" : this.getStyle("z-index")
9281             };
9282         },
9283
9284         /**
9285          * Gets the width of the border(s) for the specified side(s)
9286          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
9287          * passing lr would get the border (l)eft width + the border (r)ight width.
9288          * @return {Number} The width of the sides passed added together
9289          */
9290         getBorderWidth : function(side){
9291             return this.addStyles(side, El.borders);
9292         },
9293
9294         /**
9295          * Gets the width of the padding(s) for the specified side(s)
9296          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
9297          * passing lr would get the padding (l)eft + the padding (r)ight.
9298          * @return {Number} The padding of the sides passed added together
9299          */
9300         getPadding : function(side){
9301             return this.addStyles(side, El.paddings);
9302         },
9303
9304         /**
9305         * Set positioning with an object returned by getPositioning().
9306         * @param {Object} posCfg
9307         * @return {Roo.Element} this
9308          */
9309         setPositioning : function(pc){
9310             this.applyStyles(pc);
9311             if(pc.right == "auto"){
9312                 this.dom.style.right = "";
9313             }
9314             if(pc.bottom == "auto"){
9315                 this.dom.style.bottom = "";
9316             }
9317             return this;
9318         },
9319
9320         // private
9321         fixDisplay : function(){
9322             if(this.getStyle("display") == "none"){
9323                 this.setStyle("visibility", "hidden");
9324                 this.setStyle("display", this.originalDisplay); // first try reverting to default
9325                 if(this.getStyle("display") == "none"){ // if that fails, default to block
9326                     this.setStyle("display", "block");
9327                 }
9328             }
9329         },
9330
9331         /**
9332          * Quick set left and top adding default units
9333          * @param {String} left The left CSS property value
9334          * @param {String} top The top CSS property value
9335          * @return {Roo.Element} this
9336          */
9337          setLeftTop : function(left, top){
9338             this.dom.style.left = this.addUnits(left);
9339             this.dom.style.top = this.addUnits(top);
9340             return this;
9341         },
9342
9343         /**
9344          * Move this element relative to its current position.
9345          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9346          * @param {Number} distance How far to move the element in pixels
9347          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9348          * @return {Roo.Element} this
9349          */
9350          move : function(direction, distance, animate){
9351             var xy = this.getXY();
9352             direction = direction.toLowerCase();
9353             switch(direction){
9354                 case "l":
9355                 case "left":
9356                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
9357                     break;
9358                case "r":
9359                case "right":
9360                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
9361                     break;
9362                case "t":
9363                case "top":
9364                case "up":
9365                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
9366                     break;
9367                case "b":
9368                case "bottom":
9369                case "down":
9370                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
9371                     break;
9372             }
9373             return this;
9374         },
9375
9376         /**
9377          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
9378          * @return {Roo.Element} this
9379          */
9380         clip : function(){
9381             if(!this.isClipped){
9382                this.isClipped = true;
9383                this.originalClip = {
9384                    "o": this.getStyle("overflow"),
9385                    "x": this.getStyle("overflow-x"),
9386                    "y": this.getStyle("overflow-y")
9387                };
9388                this.setStyle("overflow", "hidden");
9389                this.setStyle("overflow-x", "hidden");
9390                this.setStyle("overflow-y", "hidden");
9391             }
9392             return this;
9393         },
9394
9395         /**
9396          *  Return clipping (overflow) to original clipping before clip() was called
9397          * @return {Roo.Element} this
9398          */
9399         unclip : function(){
9400             if(this.isClipped){
9401                 this.isClipped = false;
9402                 var o = this.originalClip;
9403                 if(o.o){this.setStyle("overflow", o.o);}
9404                 if(o.x){this.setStyle("overflow-x", o.x);}
9405                 if(o.y){this.setStyle("overflow-y", o.y);}
9406             }
9407             return this;
9408         },
9409
9410
9411         /**
9412          * Gets the x,y coordinates specified by the anchor position on the element.
9413          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
9414          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
9415          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
9416          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
9417          * @return {Array} [x, y] An array containing the element's x and y coordinates
9418          */
9419         getAnchorXY : function(anchor, local, s){
9420             //Passing a different size is useful for pre-calculating anchors,
9421             //especially for anchored animations that change the el size.
9422
9423             var w, h, vp = false;
9424             if(!s){
9425                 var d = this.dom;
9426                 if(d == document.body || d == document){
9427                     vp = true;
9428                     w = D.getViewWidth(); h = D.getViewHeight();
9429                 }else{
9430                     w = this.getWidth(); h = this.getHeight();
9431                 }
9432             }else{
9433                 w = s.width;  h = s.height;
9434             }
9435             var x = 0, y = 0, r = Math.round;
9436             switch((anchor || "tl").toLowerCase()){
9437                 case "c":
9438                     x = r(w*.5);
9439                     y = r(h*.5);
9440                 break;
9441                 case "t":
9442                     x = r(w*.5);
9443                     y = 0;
9444                 break;
9445                 case "l":
9446                     x = 0;
9447                     y = r(h*.5);
9448                 break;
9449                 case "r":
9450                     x = w;
9451                     y = r(h*.5);
9452                 break;
9453                 case "b":
9454                     x = r(w*.5);
9455                     y = h;
9456                 break;
9457                 case "tl":
9458                     x = 0;
9459                     y = 0;
9460                 break;
9461                 case "bl":
9462                     x = 0;
9463                     y = h;
9464                 break;
9465                 case "br":
9466                     x = w;
9467                     y = h;
9468                 break;
9469                 case "tr":
9470                     x = w;
9471                     y = 0;
9472                 break;
9473             }
9474             if(local === true){
9475                 return [x, y];
9476             }
9477             if(vp){
9478                 var sc = this.getScroll();
9479                 return [x + sc.left, y + sc.top];
9480             }
9481             //Add the element's offset xy
9482             var o = this.getXY();
9483             return [x+o[0], y+o[1]];
9484         },
9485
9486         /**
9487          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
9488          * supported position values.
9489          * @param {String/HTMLElement/Roo.Element} element The element to align to.
9490          * @param {String} position The position to align to.
9491          * @param {Array} offsets (optional) Offset the positioning by [x, y]
9492          * @return {Array} [x, y]
9493          */
9494         getAlignToXY : function(el, p, o)
9495         {
9496             el = Roo.get(el);
9497             var d = this.dom;
9498             if(!el.dom){
9499                 throw "Element.alignTo with an element that doesn't exist";
9500             }
9501             var c = false; //constrain to viewport
9502             var p1 = "", p2 = "";
9503             o = o || [0,0];
9504
9505             if(!p){
9506                 p = "tl-bl";
9507             }else if(p == "?"){
9508                 p = "tl-bl?";
9509             }else if(p.indexOf("-") == -1){
9510                 p = "tl-" + p;
9511             }
9512             p = p.toLowerCase();
9513             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
9514             if(!m){
9515                throw "Element.alignTo with an invalid alignment " + p;
9516             }
9517             p1 = m[1]; p2 = m[2]; c = !!m[3];
9518
9519             //Subtract the aligned el's internal xy from the target's offset xy
9520             //plus custom offset to get the aligned el's new offset xy
9521             var a1 = this.getAnchorXY(p1, true);
9522             var a2 = el.getAnchorXY(p2, false);
9523             var x = a2[0] - a1[0] + o[0];
9524             var y = a2[1] - a1[1] + o[1];
9525             if(c){
9526                 //constrain the aligned el to viewport if necessary
9527                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
9528                 // 5px of margin for ie
9529                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
9530
9531                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
9532                 //perpendicular to the vp border, allow the aligned el to slide on that border,
9533                 //otherwise swap the aligned el to the opposite border of the target.
9534                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
9535                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
9536                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t")  );
9537                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
9538
9539                var doc = document;
9540                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
9541                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
9542
9543                if((x+w) > dw + scrollX){
9544                     x = swapX ? r.left-w : dw+scrollX-w;
9545                 }
9546                if(x < scrollX){
9547                    x = swapX ? r.right : scrollX;
9548                }
9549                if((y+h) > dh + scrollY){
9550                     y = swapY ? r.top-h : dh+scrollY-h;
9551                 }
9552                if (y < scrollY){
9553                    y = swapY ? r.bottom : scrollY;
9554                }
9555             }
9556             return [x,y];
9557         },
9558
9559         // private
9560         getConstrainToXY : function(){
9561             var os = {top:0, left:0, bottom:0, right: 0};
9562
9563             return function(el, local, offsets, proposedXY){
9564                 el = Roo.get(el);
9565                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
9566
9567                 var vw, vh, vx = 0, vy = 0;
9568                 if(el.dom == document.body || el.dom == document){
9569                     vw = Roo.lib.Dom.getViewWidth();
9570                     vh = Roo.lib.Dom.getViewHeight();
9571                 }else{
9572                     vw = el.dom.clientWidth;
9573                     vh = el.dom.clientHeight;
9574                     if(!local){
9575                         var vxy = el.getXY();
9576                         vx = vxy[0];
9577                         vy = vxy[1];
9578                     }
9579                 }
9580
9581                 var s = el.getScroll();
9582
9583                 vx += offsets.left + s.left;
9584                 vy += offsets.top + s.top;
9585
9586                 vw -= offsets.right;
9587                 vh -= offsets.bottom;
9588
9589                 var vr = vx+vw;
9590                 var vb = vy+vh;
9591
9592                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
9593                 var x = xy[0], y = xy[1];
9594                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
9595
9596                 // only move it if it needs it
9597                 var moved = false;
9598
9599                 // first validate right/bottom
9600                 if((x + w) > vr){
9601                     x = vr - w;
9602                     moved = true;
9603                 }
9604                 if((y + h) > vb){
9605                     y = vb - h;
9606                     moved = true;
9607                 }
9608                 // then make sure top/left isn't negative
9609                 if(x < vx){
9610                     x = vx;
9611                     moved = true;
9612                 }
9613                 if(y < vy){
9614                     y = vy;
9615                     moved = true;
9616                 }
9617                 return moved ? [x, y] : false;
9618             };
9619         }(),
9620
9621         // private
9622         adjustForConstraints : function(xy, parent, offsets){
9623             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
9624         },
9625
9626         /**
9627          * Aligns this element with another element relative to the specified anchor points. If the other element is the
9628          * document it aligns it to the viewport.
9629          * The position parameter is optional, and can be specified in any one of the following formats:
9630          * <ul>
9631          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
9632          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
9633          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
9634          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
9635          *   <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
9636          *       element's anchor point, and the second value is used as the target's anchor point.</li>
9637          * </ul>
9638          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
9639          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
9640          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
9641          * that specified in order to enforce the viewport constraints.
9642          * Following are all of the supported anchor positions:
9643     <pre>
9644     Value  Description
9645     -----  -----------------------------
9646     tl     The top left corner (default)
9647     t      The center of the top edge
9648     tr     The top right corner
9649     l      The center of the left edge
9650     c      In the center of the element
9651     r      The center of the right edge
9652     bl     The bottom left corner
9653     b      The center of the bottom edge
9654     br     The bottom right corner
9655     </pre>
9656     Example Usage:
9657     <pre><code>
9658     // align el to other-el using the default positioning ("tl-bl", non-constrained)
9659     el.alignTo("other-el");
9660
9661     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
9662     el.alignTo("other-el", "tr?");
9663
9664     // align the bottom right corner of el with the center left edge of other-el
9665     el.alignTo("other-el", "br-l?");
9666
9667     // align the center of el with the bottom left corner of other-el and
9668     // adjust the x position by -6 pixels (and the y position by 0)
9669     el.alignTo("other-el", "c-bl", [-6, 0]);
9670     </code></pre>
9671          * @param {String/HTMLElement/Roo.Element} element The element to align to.
9672          * @param {String} position The position to align to.
9673          * @param {Array} offsets (optional) Offset the positioning by [x, y]
9674          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9675          * @return {Roo.Element} this
9676          */
9677         alignTo : function(element, position, offsets, animate){
9678             var xy = this.getAlignToXY(element, position, offsets);
9679             this.setXY(xy, this.preanim(arguments, 3));
9680             return this;
9681         },
9682
9683         /**
9684          * Anchors an element to another element and realigns it when the window is resized.
9685          * @param {String/HTMLElement/Roo.Element} element The element to align to.
9686          * @param {String} position The position to align to.
9687          * @param {Array} offsets (optional) Offset the positioning by [x, y]
9688          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
9689          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
9690          * is a number, it is used as the buffer delay (defaults to 50ms).
9691          * @param {Function} callback The function to call after the animation finishes
9692          * @return {Roo.Element} this
9693          */
9694         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
9695             var action = function(){
9696                 this.alignTo(el, alignment, offsets, animate);
9697                 Roo.callback(callback, this);
9698             };
9699             Roo.EventManager.onWindowResize(action, this);
9700             var tm = typeof monitorScroll;
9701             if(tm != 'undefined'){
9702                 Roo.EventManager.on(window, 'scroll', action, this,
9703                     {buffer: tm == 'number' ? monitorScroll : 50});
9704             }
9705             action.call(this); // align immediately
9706             return this;
9707         },
9708         /**
9709          * Clears any opacity settings from this element. Required in some cases for IE.
9710          * @return {Roo.Element} this
9711          */
9712         clearOpacity : function(){
9713             if (window.ActiveXObject) {
9714                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
9715                     this.dom.style.filter = "";
9716                 }
9717             } else {
9718                 this.dom.style.opacity = "";
9719                 this.dom.style["-moz-opacity"] = "";
9720                 this.dom.style["-khtml-opacity"] = "";
9721             }
9722             return this;
9723         },
9724
9725         /**
9726          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
9727          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9728          * @return {Roo.Element} this
9729          */
9730         hide : function(animate){
9731             this.setVisible(false, this.preanim(arguments, 0));
9732             return this;
9733         },
9734
9735         /**
9736         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
9737         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9738          * @return {Roo.Element} this
9739          */
9740         show : function(animate){
9741             this.setVisible(true, this.preanim(arguments, 0));
9742             return this;
9743         },
9744
9745         /**
9746          * @private Test if size has a unit, otherwise appends the default
9747          */
9748         addUnits : function(size){
9749             return Roo.Element.addUnits(size, this.defaultUnit);
9750         },
9751
9752         /**
9753          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
9754          * @return {Roo.Element} this
9755          */
9756         beginMeasure : function(){
9757             var el = this.dom;
9758             if(el.offsetWidth || el.offsetHeight){
9759                 return this; // offsets work already
9760             }
9761             var changed = [];
9762             var p = this.dom, b = document.body; // start with this element
9763             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
9764                 var pe = Roo.get(p);
9765                 if(pe.getStyle('display') == 'none'){
9766                     changed.push({el: p, visibility: pe.getStyle("visibility")});
9767                     p.style.visibility = "hidden";
9768                     p.style.display = "block";
9769                 }
9770                 p = p.parentNode;
9771             }
9772             this._measureChanged = changed;
9773             return this;
9774
9775         },
9776
9777         /**
9778          * Restores displays to before beginMeasure was called
9779          * @return {Roo.Element} this
9780          */
9781         endMeasure : function(){
9782             var changed = this._measureChanged;
9783             if(changed){
9784                 for(var i = 0, len = changed.length; i < len; i++) {
9785                     var r = changed[i];
9786                     r.el.style.visibility = r.visibility;
9787                     r.el.style.display = "none";
9788                 }
9789                 this._measureChanged = null;
9790             }
9791             return this;
9792         },
9793
9794         /**
9795         * Update the innerHTML of this element, optionally searching for and processing scripts
9796         * @param {String} html The new HTML
9797         * @param {Boolean} loadScripts (optional) true to look for and process scripts
9798         * @param {Function} callback For async script loading you can be noticed when the update completes
9799         * @return {Roo.Element} this
9800          */
9801         update : function(html, loadScripts, callback){
9802             if(typeof html == "undefined"){
9803                 html = "";
9804             }
9805             if(loadScripts !== true){
9806                 this.dom.innerHTML = html;
9807                 if(typeof callback == "function"){
9808                     callback();
9809                 }
9810                 return this;
9811             }
9812             var id = Roo.id();
9813             var dom = this.dom;
9814
9815             html += '<span id="' + id + '"></span>';
9816
9817             E.onAvailable(id, function(){
9818                 var hd = document.getElementsByTagName("head")[0];
9819                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
9820                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
9821                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
9822
9823                 var match;
9824                 while(match = re.exec(html)){
9825                     var attrs = match[1];
9826                     var srcMatch = attrs ? attrs.match(srcRe) : false;
9827                     if(srcMatch && srcMatch[2]){
9828                        var s = document.createElement("script");
9829                        s.src = srcMatch[2];
9830                        var typeMatch = attrs.match(typeRe);
9831                        if(typeMatch && typeMatch[2]){
9832                            s.type = typeMatch[2];
9833                        }
9834                        hd.appendChild(s);
9835                     }else if(match[2] && match[2].length > 0){
9836                         if(window.execScript) {
9837                            window.execScript(match[2]);
9838                         } else {
9839                             /**
9840                              * eval:var:id
9841                              * eval:var:dom
9842                              * eval:var:html
9843                              * 
9844                              */
9845                            window.eval(match[2]);
9846                         }
9847                     }
9848                 }
9849                 var el = document.getElementById(id);
9850                 if(el){el.parentNode.removeChild(el);}
9851                 if(typeof callback == "function"){
9852                     callback();
9853                 }
9854             });
9855             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
9856             return this;
9857         },
9858
9859         /**
9860          * Direct access to the UpdateManager update() method (takes the same parameters).
9861          * @param {String/Function} url The url for this request or a function to call to get the url
9862          * @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}
9863          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
9864          * @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.
9865          * @return {Roo.Element} this
9866          */
9867         load : function(){
9868             var um = this.getUpdateManager();
9869             um.update.apply(um, arguments);
9870             return this;
9871         },
9872
9873         /**
9874         * Gets this element's UpdateManager
9875         * @return {Roo.UpdateManager} The UpdateManager
9876         */
9877         getUpdateManager : function(){
9878             if(!this.updateManager){
9879                 this.updateManager = new Roo.UpdateManager(this);
9880             }
9881             return this.updateManager;
9882         },
9883
9884         /**
9885          * Disables text selection for this element (normalized across browsers)
9886          * @return {Roo.Element} this
9887          */
9888         unselectable : function(){
9889             this.dom.unselectable = "on";
9890             this.swallowEvent("selectstart", true);
9891             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
9892             this.addClass("x-unselectable");
9893             return this;
9894         },
9895
9896         /**
9897         * Calculates the x, y to center this element on the screen
9898         * @return {Array} The x, y values [x, y]
9899         */
9900         getCenterXY : function(){
9901             return this.getAlignToXY(document, 'c-c');
9902         },
9903
9904         /**
9905         * Centers the Element in either the viewport, or another Element.
9906         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
9907         */
9908         center : function(centerIn){
9909             this.alignTo(centerIn || document, 'c-c');
9910             return this;
9911         },
9912
9913         /**
9914          * Tests various css rules/browsers to determine if this element uses a border box
9915          * @return {Boolean}
9916          */
9917         isBorderBox : function(){
9918             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
9919         },
9920
9921         /**
9922          * Return a box {x, y, width, height} that can be used to set another elements
9923          * size/location to match this element.
9924          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
9925          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
9926          * @return {Object} box An object in the format {x, y, width, height}
9927          */
9928         getBox : function(contentBox, local){
9929             var xy;
9930             if(!local){
9931                 xy = this.getXY();
9932             }else{
9933                 var left = parseInt(this.getStyle("left"), 10) || 0;
9934                 var top = parseInt(this.getStyle("top"), 10) || 0;
9935                 xy = [left, top];
9936             }
9937             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
9938             if(!contentBox){
9939                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
9940             }else{
9941                 var l = this.getBorderWidth("l")+this.getPadding("l");
9942                 var r = this.getBorderWidth("r")+this.getPadding("r");
9943                 var t = this.getBorderWidth("t")+this.getPadding("t");
9944                 var b = this.getBorderWidth("b")+this.getPadding("b");
9945                 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)};
9946             }
9947             bx.right = bx.x + bx.width;
9948             bx.bottom = bx.y + bx.height;
9949             return bx;
9950         },
9951
9952         /**
9953          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
9954          for more information about the sides.
9955          * @param {String} sides
9956          * @return {Number}
9957          */
9958         getFrameWidth : function(sides, onlyContentBox){
9959             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
9960         },
9961
9962         /**
9963          * 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.
9964          * @param {Object} box The box to fill {x, y, width, height}
9965          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
9966          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9967          * @return {Roo.Element} this
9968          */
9969         setBox : function(box, adjust, animate){
9970             var w = box.width, h = box.height;
9971             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
9972                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
9973                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
9974             }
9975             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
9976             return this;
9977         },
9978
9979         /**
9980          * Forces the browser to repaint this element
9981          * @return {Roo.Element} this
9982          */
9983          repaint : function(){
9984             var dom = this.dom;
9985             this.addClass("x-repaint");
9986             setTimeout(function(){
9987                 Roo.get(dom).removeClass("x-repaint");
9988             }, 1);
9989             return this;
9990         },
9991
9992         /**
9993          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
9994          * then it returns the calculated width of the sides (see getPadding)
9995          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
9996          * @return {Object/Number}
9997          */
9998         getMargins : function(side){
9999             if(!side){
10000                 return {
10001                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
10002                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
10003                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
10004                     right: parseInt(this.getStyle("margin-right"), 10) || 0
10005                 };
10006             }else{
10007                 return this.addStyles(side, El.margins);
10008              }
10009         },
10010
10011         // private
10012         addStyles : function(sides, styles){
10013             var val = 0, v, w;
10014             for(var i = 0, len = sides.length; i < len; i++){
10015                 v = this.getStyle(styles[sides.charAt(i)]);
10016                 if(v){
10017                      w = parseInt(v, 10);
10018                      if(w){ val += w; }
10019                 }
10020             }
10021             return val;
10022         },
10023
10024         /**
10025          * Creates a proxy element of this element
10026          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
10027          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
10028          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
10029          * @return {Roo.Element} The new proxy element
10030          */
10031         createProxy : function(config, renderTo, matchBox){
10032             if(renderTo){
10033                 renderTo = Roo.getDom(renderTo);
10034             }else{
10035                 renderTo = document.body;
10036             }
10037             config = typeof config == "object" ?
10038                 config : {tag : "div", cls: config};
10039             var proxy = Roo.DomHelper.append(renderTo, config, true);
10040             if(matchBox){
10041                proxy.setBox(this.getBox());
10042             }
10043             return proxy;
10044         },
10045
10046         /**
10047          * Puts a mask over this element to disable user interaction. Requires core.css.
10048          * This method can only be applied to elements which accept child nodes.
10049          * @param {String} msg (optional) A message to display in the mask
10050          * @param {String} msgCls (optional) A css class to apply to the msg element - use no-spinner to hide the spinner on bootstrap
10051          * @return {Element} The mask  element
10052          */
10053         mask : function(msg, msgCls)
10054         {
10055             if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
10056                 this.setStyle("position", "relative");
10057             }
10058             if(!this._mask){
10059                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
10060             }
10061             
10062             this.addClass("x-masked");
10063             this._mask.setDisplayed(true);
10064             
10065             // we wander
10066             var z = 0;
10067             var dom = this.dom;
10068             while (dom && dom.style) {
10069                 if (!isNaN(parseInt(dom.style.zIndex))) {
10070                     z = Math.max(z, parseInt(dom.style.zIndex));
10071                 }
10072                 dom = dom.parentNode;
10073             }
10074             // if we are masking the body - then it hides everything..
10075             if (this.dom == document.body) {
10076                 z = 1000000;
10077                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
10078                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
10079             }
10080            
10081             if(typeof msg == 'string'){
10082                 if(!this._maskMsg){
10083                     this._maskMsg = Roo.DomHelper.append(this.dom, {
10084                         cls: "roo-el-mask-msg", 
10085                         cn: [
10086                             {
10087                                 tag: 'i',
10088                                 cls: 'fa fa-spinner fa-spin'
10089                             },
10090                             {
10091                                 tag: 'div'
10092                             }   
10093                         ]
10094                     }, true);
10095                 }
10096                 var mm = this._maskMsg;
10097                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
10098                 if (mm.dom.lastChild) { // weird IE issue?
10099                     mm.dom.lastChild.innerHTML = msg;
10100                 }
10101                 mm.setDisplayed(true);
10102                 mm.center(this);
10103                 mm.setStyle('z-index', z + 102);
10104             }
10105             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
10106                 this._mask.setHeight(this.getHeight());
10107             }
10108             this._mask.setStyle('z-index', z + 100);
10109             
10110             return this._mask;
10111         },
10112
10113         /**
10114          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
10115          * it is cached for reuse.
10116          */
10117         unmask : function(removeEl){
10118             if(this._mask){
10119                 if(removeEl === true){
10120                     this._mask.remove();
10121                     delete this._mask;
10122                     if(this._maskMsg){
10123                         this._maskMsg.remove();
10124                         delete this._maskMsg;
10125                     }
10126                 }else{
10127                     this._mask.setDisplayed(false);
10128                     if(this._maskMsg){
10129                         this._maskMsg.setDisplayed(false);
10130                     }
10131                 }
10132             }
10133             this.removeClass("x-masked");
10134         },
10135
10136         /**
10137          * Returns true if this element is masked
10138          * @return {Boolean}
10139          */
10140         isMasked : function(){
10141             return this._mask && this._mask.isVisible();
10142         },
10143
10144         /**
10145          * Creates an iframe shim for this element to keep selects and other windowed objects from
10146          * showing through.
10147          * @return {Roo.Element} The new shim element
10148          */
10149         createShim : function(){
10150             var el = document.createElement('iframe');
10151             el.frameBorder = 'no';
10152             el.className = 'roo-shim';
10153             if(Roo.isIE && Roo.isSecure){
10154                 el.src = Roo.SSL_SECURE_URL;
10155             }
10156             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
10157             shim.autoBoxAdjust = false;
10158             return shim;
10159         },
10160
10161         /**
10162          * Removes this element from the DOM and deletes it from the cache
10163          */
10164         remove : function(){
10165             if(this.dom.parentNode){
10166                 this.dom.parentNode.removeChild(this.dom);
10167             }
10168             delete El.cache[this.dom.id];
10169         },
10170
10171         /**
10172          * Sets up event handlers to add and remove a css class when the mouse is over this element
10173          * @param {String} className
10174          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
10175          * mouseout events for children elements
10176          * @return {Roo.Element} this
10177          */
10178         addClassOnOver : function(className, preventFlicker){
10179             this.on("mouseover", function(){
10180                 Roo.fly(this, '_internal').addClass(className);
10181             }, this.dom);
10182             var removeFn = function(e){
10183                 if(preventFlicker !== true || !e.within(this, true)){
10184                     Roo.fly(this, '_internal').removeClass(className);
10185                 }
10186             };
10187             this.on("mouseout", removeFn, this.dom);
10188             return this;
10189         },
10190
10191         /**
10192          * Sets up event handlers to add and remove a css class when this element has the focus
10193          * @param {String} className
10194          * @return {Roo.Element} this
10195          */
10196         addClassOnFocus : function(className){
10197             this.on("focus", function(){
10198                 Roo.fly(this, '_internal').addClass(className);
10199             }, this.dom);
10200             this.on("blur", function(){
10201                 Roo.fly(this, '_internal').removeClass(className);
10202             }, this.dom);
10203             return this;
10204         },
10205         /**
10206          * 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)
10207          * @param {String} className
10208          * @return {Roo.Element} this
10209          */
10210         addClassOnClick : function(className){
10211             var dom = this.dom;
10212             this.on("mousedown", function(){
10213                 Roo.fly(dom, '_internal').addClass(className);
10214                 var d = Roo.get(document);
10215                 var fn = function(){
10216                     Roo.fly(dom, '_internal').removeClass(className);
10217                     d.removeListener("mouseup", fn);
10218                 };
10219                 d.on("mouseup", fn);
10220             });
10221             return this;
10222         },
10223
10224         /**
10225          * Stops the specified event from bubbling and optionally prevents the default action
10226          * @param {String} eventName
10227          * @param {Boolean} preventDefault (optional) true to prevent the default action too
10228          * @return {Roo.Element} this
10229          */
10230         swallowEvent : function(eventName, preventDefault){
10231             var fn = function(e){
10232                 e.stopPropagation();
10233                 if(preventDefault){
10234                     e.preventDefault();
10235                 }
10236             };
10237             if(eventName instanceof Array){
10238                 for(var i = 0, len = eventName.length; i < len; i++){
10239                      this.on(eventName[i], fn);
10240                 }
10241                 return this;
10242             }
10243             this.on(eventName, fn);
10244             return this;
10245         },
10246
10247         /**
10248          * @private
10249          */
10250         fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
10251
10252         /**
10253          * Sizes this element to its parent element's dimensions performing
10254          * neccessary box adjustments.
10255          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
10256          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
10257          * @return {Roo.Element} this
10258          */
10259         fitToParent : function(monitorResize, targetParent) {
10260           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
10261           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
10262           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
10263             return this;
10264           }
10265           var p = Roo.get(targetParent || this.dom.parentNode);
10266           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
10267           if (monitorResize === true) {
10268             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
10269             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
10270           }
10271           return this;
10272         },
10273
10274         /**
10275          * Gets the next sibling, skipping text nodes
10276          * @return {HTMLElement} The next sibling or null
10277          */
10278         getNextSibling : function(){
10279             var n = this.dom.nextSibling;
10280             while(n && n.nodeType != 1){
10281                 n = n.nextSibling;
10282             }
10283             return n;
10284         },
10285
10286         /**
10287          * Gets the previous sibling, skipping text nodes
10288          * @return {HTMLElement} The previous sibling or null
10289          */
10290         getPrevSibling : function(){
10291             var n = this.dom.previousSibling;
10292             while(n && n.nodeType != 1){
10293                 n = n.previousSibling;
10294             }
10295             return n;
10296         },
10297
10298
10299         /**
10300          * Appends the passed element(s) to this element
10301          * @param {String/HTMLElement/Array/Element/CompositeElement} el
10302          * @return {Roo.Element} this
10303          */
10304         appendChild: function(el){
10305             el = Roo.get(el);
10306             el.appendTo(this);
10307             return this;
10308         },
10309
10310         /**
10311          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
10312          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
10313          * automatically generated with the specified attributes.
10314          * @param {HTMLElement} insertBefore (optional) a child element of this element
10315          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
10316          * @return {Roo.Element} The new child element
10317          */
10318         createChild: function(config, insertBefore, returnDom){
10319             config = config || {tag:'div'};
10320             if(insertBefore){
10321                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
10322             }
10323             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
10324         },
10325
10326         /**
10327          * Appends this element to the passed element
10328          * @param {String/HTMLElement/Element} el The new parent element
10329          * @return {Roo.Element} this
10330          */
10331         appendTo: function(el){
10332             el = Roo.getDom(el);
10333             el.appendChild(this.dom);
10334             return this;
10335         },
10336
10337         /**
10338          * Inserts this element before the passed element in the DOM
10339          * @param {String/HTMLElement/Element} el The element to insert before
10340          * @return {Roo.Element} this
10341          */
10342         insertBefore: function(el){
10343             el = Roo.getDom(el);
10344             el.parentNode.insertBefore(this.dom, el);
10345             return this;
10346         },
10347
10348         /**
10349          * Inserts this element after the passed element in the DOM
10350          * @param {String/HTMLElement/Element} el The element to insert after
10351          * @return {Roo.Element} this
10352          */
10353         insertAfter: function(el){
10354             el = Roo.getDom(el);
10355             el.parentNode.insertBefore(this.dom, el.nextSibling);
10356             return this;
10357         },
10358
10359         /**
10360          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
10361          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
10362          * @return {Roo.Element} The new child
10363          */
10364         insertFirst: function(el, returnDom){
10365             el = el || {};
10366             if(typeof el == 'object' && !el.nodeType){ // dh config
10367                 return this.createChild(el, this.dom.firstChild, returnDom);
10368             }else{
10369                 el = Roo.getDom(el);
10370                 this.dom.insertBefore(el, this.dom.firstChild);
10371                 return !returnDom ? Roo.get(el) : el;
10372             }
10373         },
10374
10375         /**
10376          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
10377          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
10378          * @param {String} where (optional) 'before' or 'after' defaults to before
10379          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
10380          * @return {Roo.Element} the inserted Element
10381          */
10382         insertSibling: function(el, where, returnDom){
10383             where = where ? where.toLowerCase() : 'before';
10384             el = el || {};
10385             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
10386
10387             if(typeof el == 'object' && !el.nodeType){ // dh config
10388                 if(where == 'after' && !this.dom.nextSibling){
10389                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
10390                 }else{
10391                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
10392                 }
10393
10394             }else{
10395                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
10396                             where == 'before' ? this.dom : this.dom.nextSibling);
10397                 if(!returnDom){
10398                     rt = Roo.get(rt);
10399                 }
10400             }
10401             return rt;
10402         },
10403
10404         /**
10405          * Creates and wraps this element with another element
10406          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
10407          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
10408          * @return {HTMLElement/Element} The newly created wrapper element
10409          */
10410         wrap: function(config, returnDom){
10411             if(!config){
10412                 config = {tag: "div"};
10413             }
10414             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
10415             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
10416             return newEl;
10417         },
10418
10419         /**
10420          * Replaces the passed element with this element
10421          * @param {String/HTMLElement/Element} el The element to replace
10422          * @return {Roo.Element} this
10423          */
10424         replace: function(el){
10425             el = Roo.get(el);
10426             this.insertBefore(el);
10427             el.remove();
10428             return this;
10429         },
10430
10431         /**
10432          * Inserts an html fragment into this element
10433          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
10434          * @param {String} html The HTML fragment
10435          * @param {Boolean} returnEl True to return an Roo.Element
10436          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
10437          */
10438         insertHtml : function(where, html, returnEl){
10439             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
10440             return returnEl ? Roo.get(el) : el;
10441         },
10442
10443         /**
10444          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
10445          * @param {Object} o The object with the attributes
10446          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
10447          * @return {Roo.Element} this
10448          */
10449         set : function(o, useSet){
10450             var el = this.dom;
10451             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
10452             for(var attr in o){
10453                 if(attr == "style" || typeof o[attr] == "function")  { continue; }
10454                 if(attr=="cls"){
10455                     el.className = o["cls"];
10456                 }else{
10457                     if(useSet) {
10458                         el.setAttribute(attr, o[attr]);
10459                     } else {
10460                         el[attr] = o[attr];
10461                     }
10462                 }
10463             }
10464             if(o.style){
10465                 Roo.DomHelper.applyStyles(el, o.style);
10466             }
10467             return this;
10468         },
10469
10470         /**
10471          * Convenience method for constructing a KeyMap
10472          * @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:
10473          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
10474          * @param {Function} fn The function to call
10475          * @param {Object} scope (optional) The scope of the function
10476          * @return {Roo.KeyMap} The KeyMap created
10477          */
10478         addKeyListener : function(key, fn, scope){
10479             var config;
10480             if(typeof key != "object" || key instanceof Array){
10481                 config = {
10482                     key: key,
10483                     fn: fn,
10484                     scope: scope
10485                 };
10486             }else{
10487                 config = {
10488                     key : key.key,
10489                     shift : key.shift,
10490                     ctrl : key.ctrl,
10491                     alt : key.alt,
10492                     fn: fn,
10493                     scope: scope
10494                 };
10495             }
10496             return new Roo.KeyMap(this, config);
10497         },
10498
10499         /**
10500          * Creates a KeyMap for this element
10501          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
10502          * @return {Roo.KeyMap} The KeyMap created
10503          */
10504         addKeyMap : function(config){
10505             return new Roo.KeyMap(this, config);
10506         },
10507
10508         /**
10509          * Returns true if this element is scrollable.
10510          * @return {Boolean}
10511          */
10512          isScrollable : function(){
10513             var dom = this.dom;
10514             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
10515         },
10516
10517         /**
10518          * 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().
10519          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
10520          * @param {Number} value The new scroll value
10521          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10522          * @return {Element} this
10523          */
10524
10525         scrollTo : function(side, value, animate){
10526             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
10527             if(!animate || !A){
10528                 this.dom[prop] = value;
10529             }else{
10530                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
10531                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
10532             }
10533             return this;
10534         },
10535
10536         /**
10537          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
10538          * within this element's scrollable range.
10539          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
10540          * @param {Number} distance How far to scroll the element in pixels
10541          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10542          * @return {Boolean} Returns true if a scroll was triggered or false if the element
10543          * was scrolled as far as it could go.
10544          */
10545          scroll : function(direction, distance, animate){
10546              if(!this.isScrollable()){
10547                  return;
10548              }
10549              var el = this.dom;
10550              var l = el.scrollLeft, t = el.scrollTop;
10551              var w = el.scrollWidth, h = el.scrollHeight;
10552              var cw = el.clientWidth, ch = el.clientHeight;
10553              direction = direction.toLowerCase();
10554              var scrolled = false;
10555              var a = this.preanim(arguments, 2);
10556              switch(direction){
10557                  case "l":
10558                  case "left":
10559                      if(w - l > cw){
10560                          var v = Math.min(l + distance, w-cw);
10561                          this.scrollTo("left", v, a);
10562                          scrolled = true;
10563                      }
10564                      break;
10565                 case "r":
10566                 case "right":
10567                      if(l > 0){
10568                          var v = Math.max(l - distance, 0);
10569                          this.scrollTo("left", v, a);
10570                          scrolled = true;
10571                      }
10572                      break;
10573                 case "t":
10574                 case "top":
10575                 case "up":
10576                      if(t > 0){
10577                          var v = Math.max(t - distance, 0);
10578                          this.scrollTo("top", v, a);
10579                          scrolled = true;
10580                      }
10581                      break;
10582                 case "b":
10583                 case "bottom":
10584                 case "down":
10585                      if(h - t > ch){
10586                          var v = Math.min(t + distance, h-ch);
10587                          this.scrollTo("top", v, a);
10588                          scrolled = true;
10589                      }
10590                      break;
10591              }
10592              return scrolled;
10593         },
10594
10595         /**
10596          * Translates the passed page coordinates into left/top css values for this element
10597          * @param {Number/Array} x The page x or an array containing [x, y]
10598          * @param {Number} y The page y
10599          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
10600          */
10601         translatePoints : function(x, y){
10602             if(typeof x == 'object' || x instanceof Array){
10603                 y = x[1]; x = x[0];
10604             }
10605             var p = this.getStyle('position');
10606             var o = this.getXY();
10607
10608             var l = parseInt(this.getStyle('left'), 10);
10609             var t = parseInt(this.getStyle('top'), 10);
10610
10611             if(isNaN(l)){
10612                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
10613             }
10614             if(isNaN(t)){
10615                 t = (p == "relative") ? 0 : this.dom.offsetTop;
10616             }
10617
10618             return {left: (x - o[0] + l), top: (y - o[1] + t)};
10619         },
10620
10621         /**
10622          * Returns the current scroll position of the element.
10623          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
10624          */
10625         getScroll : function(){
10626             var d = this.dom, doc = document;
10627             if(d == doc || d == doc.body){
10628                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
10629                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
10630                 return {left: l, top: t};
10631             }else{
10632                 return {left: d.scrollLeft, top: d.scrollTop};
10633             }
10634         },
10635
10636         /**
10637          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
10638          * are convert to standard 6 digit hex color.
10639          * @param {String} attr The css attribute
10640          * @param {String} defaultValue The default value to use when a valid color isn't found
10641          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
10642          * YUI color anims.
10643          */
10644         getColor : function(attr, defaultValue, prefix){
10645             var v = this.getStyle(attr);
10646             if(!v || v == "transparent" || v == "inherit") {
10647                 return defaultValue;
10648             }
10649             var color = typeof prefix == "undefined" ? "#" : prefix;
10650             if(v.substr(0, 4) == "rgb("){
10651                 var rvs = v.slice(4, v.length -1).split(",");
10652                 for(var i = 0; i < 3; i++){
10653                     var h = parseInt(rvs[i]).toString(16);
10654                     if(h < 16){
10655                         h = "0" + h;
10656                     }
10657                     color += h;
10658                 }
10659             } else {
10660                 if(v.substr(0, 1) == "#"){
10661                     if(v.length == 4) {
10662                         for(var i = 1; i < 4; i++){
10663                             var c = v.charAt(i);
10664                             color +=  c + c;
10665                         }
10666                     }else if(v.length == 7){
10667                         color += v.substr(1);
10668                     }
10669                 }
10670             }
10671             return(color.length > 5 ? color.toLowerCase() : defaultValue);
10672         },
10673
10674         /**
10675          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
10676          * gradient background, rounded corners and a 4-way shadow.
10677          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
10678          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
10679          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
10680          * @return {Roo.Element} this
10681          */
10682         boxWrap : function(cls){
10683             cls = cls || 'x-box';
10684             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
10685             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
10686             return el;
10687         },
10688
10689         /**
10690          * Returns the value of a namespaced attribute from the element's underlying DOM node.
10691          * @param {String} namespace The namespace in which to look for the attribute
10692          * @param {String} name The attribute name
10693          * @return {String} The attribute value
10694          */
10695         getAttributeNS : Roo.isIE ? function(ns, name){
10696             var d = this.dom;
10697             var type = typeof d[ns+":"+name];
10698             if(type != 'undefined' && type != 'unknown'){
10699                 return d[ns+":"+name];
10700             }
10701             return d[name];
10702         } : function(ns, name){
10703             var d = this.dom;
10704             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
10705         },
10706         
10707         
10708         /**
10709          * Sets or Returns the value the dom attribute value
10710          * @param {String|Object} name The attribute name (or object to set multiple attributes)
10711          * @param {String} value (optional) The value to set the attribute to
10712          * @return {String} The attribute value
10713          */
10714         attr : function(name){
10715             if (arguments.length > 1) {
10716                 this.dom.setAttribute(name, arguments[1]);
10717                 return arguments[1];
10718             }
10719             if (typeof(name) == 'object') {
10720                 for(var i in name) {
10721                     this.attr(i, name[i]);
10722                 }
10723                 return name;
10724             }
10725             
10726             
10727             if (!this.dom.hasAttribute(name)) {
10728                 return undefined;
10729             }
10730             return this.dom.getAttribute(name);
10731         }
10732         
10733         
10734         
10735     };
10736
10737     var ep = El.prototype;
10738
10739     /**
10740      * Appends an event handler (Shorthand for addListener)
10741      * @param {String}   eventName     The type of event to append
10742      * @param {Function} fn        The method the event invokes
10743      * @param {Object} scope       (optional) The scope (this object) of the fn
10744      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
10745      * @method
10746      */
10747     ep.on = ep.addListener;
10748         // backwards compat
10749     ep.mon = ep.addListener;
10750
10751     /**
10752      * Removes an event handler from this element (shorthand for removeListener)
10753      * @param {String} eventName the type of event to remove
10754      * @param {Function} fn the method the event invokes
10755      * @return {Roo.Element} this
10756      * @method
10757      */
10758     ep.un = ep.removeListener;
10759
10760     /**
10761      * true to automatically adjust width and height settings for box-model issues (default to true)
10762      */
10763     ep.autoBoxAdjust = true;
10764
10765     // private
10766     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
10767
10768     // private
10769     El.addUnits = function(v, defaultUnit){
10770         if(v === "" || v == "auto"){
10771             return v;
10772         }
10773         if(v === undefined){
10774             return '';
10775         }
10776         if(typeof v == "number" || !El.unitPattern.test(v)){
10777             return v + (defaultUnit || 'px');
10778         }
10779         return v;
10780     };
10781
10782     // special markup used throughout Roo when box wrapping elements
10783     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>';
10784     /**
10785      * Visibility mode constant - Use visibility to hide element
10786      * @static
10787      * @type Number
10788      */
10789     El.VISIBILITY = 1;
10790     /**
10791      * Visibility mode constant - Use display to hide element
10792      * @static
10793      * @type Number
10794      */
10795     El.DISPLAY = 2;
10796
10797     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
10798     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
10799     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
10800
10801
10802
10803     /**
10804      * @private
10805      */
10806     El.cache = {};
10807
10808     var docEl;
10809
10810     /**
10811      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
10812      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
10813      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
10814      * @return {Element} The Element object
10815      * @static
10816      */
10817     El.get = function(el){
10818         var ex, elm, id;
10819         if(!el){ return null; }
10820         if(typeof el == "string"){ // element id
10821             if(!(elm = document.getElementById(el))){
10822                 return null;
10823             }
10824             if(ex = El.cache[el]){
10825                 ex.dom = elm;
10826             }else{
10827                 ex = El.cache[el] = new El(elm);
10828             }
10829             return ex;
10830         }else if(el.tagName){ // dom element
10831             if(!(id = el.id)){
10832                 id = Roo.id(el);
10833             }
10834             if(ex = El.cache[id]){
10835                 ex.dom = el;
10836             }else{
10837                 ex = El.cache[id] = new El(el);
10838             }
10839             return ex;
10840         }else if(el instanceof El){
10841             if(el != docEl){
10842                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
10843                                                               // catch case where it hasn't been appended
10844                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
10845             }
10846             return el;
10847         }else if(el.isComposite){
10848             return el;
10849         }else if(el instanceof Array){
10850             return El.select(el);
10851         }else if(el == document){
10852             // create a bogus element object representing the document object
10853             if(!docEl){
10854                 var f = function(){};
10855                 f.prototype = El.prototype;
10856                 docEl = new f();
10857                 docEl.dom = document;
10858             }
10859             return docEl;
10860         }
10861         return null;
10862     };
10863
10864     // private
10865     El.uncache = function(el){
10866         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
10867             if(a[i]){
10868                 delete El.cache[a[i].id || a[i]];
10869             }
10870         }
10871     };
10872
10873     // private
10874     // Garbage collection - uncache elements/purge listeners on orphaned elements
10875     // so we don't hold a reference and cause the browser to retain them
10876     El.garbageCollect = function(){
10877         if(!Roo.enableGarbageCollector){
10878             clearInterval(El.collectorThread);
10879             return;
10880         }
10881         for(var eid in El.cache){
10882             var el = El.cache[eid], d = el.dom;
10883             // -------------------------------------------------------
10884             // Determining what is garbage:
10885             // -------------------------------------------------------
10886             // !d
10887             // dom node is null, definitely garbage
10888             // -------------------------------------------------------
10889             // !d.parentNode
10890             // no parentNode == direct orphan, definitely garbage
10891             // -------------------------------------------------------
10892             // !d.offsetParent && !document.getElementById(eid)
10893             // display none elements have no offsetParent so we will
10894             // also try to look it up by it's id. However, check
10895             // offsetParent first so we don't do unneeded lookups.
10896             // This enables collection of elements that are not orphans
10897             // directly, but somewhere up the line they have an orphan
10898             // parent.
10899             // -------------------------------------------------------
10900             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
10901                 delete El.cache[eid];
10902                 if(d && Roo.enableListenerCollection){
10903                     E.purgeElement(d);
10904                 }
10905             }
10906         }
10907     }
10908     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
10909
10910
10911     // dom is optional
10912     El.Flyweight = function(dom){
10913         this.dom = dom;
10914     };
10915     El.Flyweight.prototype = El.prototype;
10916
10917     El._flyweights = {};
10918     /**
10919      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
10920      * the dom node can be overwritten by other code.
10921      * @param {String/HTMLElement} el The dom node or id
10922      * @param {String} named (optional) Allows for creation of named reusable flyweights to
10923      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
10924      * @static
10925      * @return {Element} The shared Element object
10926      */
10927     El.fly = function(el, named){
10928         named = named || '_global';
10929         el = Roo.getDom(el);
10930         if(!el){
10931             return null;
10932         }
10933         if(!El._flyweights[named]){
10934             El._flyweights[named] = new El.Flyweight();
10935         }
10936         El._flyweights[named].dom = el;
10937         return El._flyweights[named];
10938     };
10939
10940     /**
10941      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
10942      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
10943      * Shorthand of {@link Roo.Element#get}
10944      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
10945      * @return {Element} The Element object
10946      * @member Roo
10947      * @method get
10948      */
10949     Roo.get = El.get;
10950     /**
10951      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
10952      * the dom node can be overwritten by other code.
10953      * Shorthand of {@link Roo.Element#fly}
10954      * @param {String/HTMLElement} el The dom node or id
10955      * @param {String} named (optional) Allows for creation of named reusable flyweights to
10956      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
10957      * @static
10958      * @return {Element} The shared Element object
10959      * @member Roo
10960      * @method fly
10961      */
10962     Roo.fly = El.fly;
10963
10964     // speedy lookup for elements never to box adjust
10965     var noBoxAdjust = Roo.isStrict ? {
10966         select:1
10967     } : {
10968         input:1, select:1, textarea:1
10969     };
10970     if(Roo.isIE || Roo.isGecko){
10971         noBoxAdjust['button'] = 1;
10972     }
10973
10974
10975     Roo.EventManager.on(window, 'unload', function(){
10976         delete El.cache;
10977         delete El._flyweights;
10978     });
10979 })();
10980
10981
10982
10983
10984 if(Roo.DomQuery){
10985     Roo.Element.selectorFunction = Roo.DomQuery.select;
10986 }
10987
10988 Roo.Element.select = function(selector, unique, root){
10989     var els;
10990     if(typeof selector == "string"){
10991         els = Roo.Element.selectorFunction(selector, root);
10992     }else if(selector.length !== undefined){
10993         els = selector;
10994     }else{
10995         throw "Invalid selector";
10996     }
10997     if(unique === true){
10998         return new Roo.CompositeElement(els);
10999     }else{
11000         return new Roo.CompositeElementLite(els);
11001     }
11002 };
11003 /**
11004  * Selects elements based on the passed CSS selector to enable working on them as 1.
11005  * @param {String/Array} selector The CSS selector or an array of elements
11006  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
11007  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
11008  * @return {CompositeElementLite/CompositeElement}
11009  * @member Roo
11010  * @method select
11011  */
11012 Roo.select = Roo.Element.select;
11013
11014
11015
11016
11017
11018
11019
11020
11021
11022
11023
11024
11025
11026
11027 /*
11028  * Based on:
11029  * Ext JS Library 1.1.1
11030  * Copyright(c) 2006-2007, Ext JS, LLC.
11031  *
11032  * Originally Released Under LGPL - original licence link has changed is not relivant.
11033  *
11034  * Fork - LGPL
11035  * <script type="text/javascript">
11036  */
11037
11038
11039
11040 //Notifies Element that fx methods are available
11041 Roo.enableFx = true;
11042
11043 /**
11044  * @class Roo.Fx
11045  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
11046  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
11047  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
11048  * Element effects to work.</p><br/>
11049  *
11050  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
11051  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
11052  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
11053  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
11054  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
11055  * expected results and should be done with care.</p><br/>
11056  *
11057  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
11058  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
11059 <pre>
11060 Value  Description
11061 -----  -----------------------------
11062 tl     The top left corner
11063 t      The center of the top edge
11064 tr     The top right corner
11065 l      The center of the left edge
11066 r      The center of the right edge
11067 bl     The bottom left corner
11068 b      The center of the bottom edge
11069 br     The bottom right corner
11070 </pre>
11071  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
11072  * below are common options that can be passed to any Fx method.</b>
11073  * @cfg {Function} callback A function called when the effect is finished
11074  * @cfg {Object} scope The scope of the effect function
11075  * @cfg {String} easing A valid Easing value for the effect
11076  * @cfg {String} afterCls A css class to apply after the effect
11077  * @cfg {Number} duration The length of time (in seconds) that the effect should last
11078  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
11079  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
11080  * effects that end with the element being visually hidden, ignored otherwise)
11081  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
11082  * a function which returns such a specification that will be applied to the Element after the effect finishes
11083  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
11084  * @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
11085  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
11086  */
11087 Roo.Fx = {
11088         /**
11089          * Slides the element into view.  An anchor point can be optionally passed to set the point of
11090          * origin for the slide effect.  This function automatically handles wrapping the element with
11091          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
11092          * Usage:
11093          *<pre><code>
11094 // default: slide the element in from the top
11095 el.slideIn();
11096
11097 // custom: slide the element in from the right with a 2-second duration
11098 el.slideIn('r', { duration: 2 });
11099
11100 // common config options shown with default values
11101 el.slideIn('t', {
11102     easing: 'easeOut',
11103     duration: .5
11104 });
11105 </code></pre>
11106          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
11107          * @param {Object} options (optional) Object literal with any of the Fx config options
11108          * @return {Roo.Element} The Element
11109          */
11110     slideIn : function(anchor, o){
11111         var el = this.getFxEl();
11112         o = o || {};
11113
11114         el.queueFx(o, function(){
11115
11116             anchor = anchor || "t";
11117
11118             // fix display to visibility
11119             this.fixDisplay();
11120
11121             // restore values after effect
11122             var r = this.getFxRestore();
11123             var b = this.getBox();
11124             // fixed size for slide
11125             this.setSize(b);
11126
11127             // wrap if needed
11128             var wrap = this.fxWrap(r.pos, o, "hidden");
11129
11130             var st = this.dom.style;
11131             st.visibility = "visible";
11132             st.position = "absolute";
11133
11134             // clear out temp styles after slide and unwrap
11135             var after = function(){
11136                 el.fxUnwrap(wrap, r.pos, o);
11137                 st.width = r.width;
11138                 st.height = r.height;
11139                 el.afterFx(o);
11140             };
11141             // time to calc the positions
11142             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
11143
11144             switch(anchor.toLowerCase()){
11145                 case "t":
11146                     wrap.setSize(b.width, 0);
11147                     st.left = st.bottom = "0";
11148                     a = {height: bh};
11149                 break;
11150                 case "l":
11151                     wrap.setSize(0, b.height);
11152                     st.right = st.top = "0";
11153                     a = {width: bw};
11154                 break;
11155                 case "r":
11156                     wrap.setSize(0, b.height);
11157                     wrap.setX(b.right);
11158                     st.left = st.top = "0";
11159                     a = {width: bw, points: pt};
11160                 break;
11161                 case "b":
11162                     wrap.setSize(b.width, 0);
11163                     wrap.setY(b.bottom);
11164                     st.left = st.top = "0";
11165                     a = {height: bh, points: pt};
11166                 break;
11167                 case "tl":
11168                     wrap.setSize(0, 0);
11169                     st.right = st.bottom = "0";
11170                     a = {width: bw, height: bh};
11171                 break;
11172                 case "bl":
11173                     wrap.setSize(0, 0);
11174                     wrap.setY(b.y+b.height);
11175                     st.right = st.top = "0";
11176                     a = {width: bw, height: bh, points: pt};
11177                 break;
11178                 case "br":
11179                     wrap.setSize(0, 0);
11180                     wrap.setXY([b.right, b.bottom]);
11181                     st.left = st.top = "0";
11182                     a = {width: bw, height: bh, points: pt};
11183                 break;
11184                 case "tr":
11185                     wrap.setSize(0, 0);
11186                     wrap.setX(b.x+b.width);
11187                     st.left = st.bottom = "0";
11188                     a = {width: bw, height: bh, points: pt};
11189                 break;
11190             }
11191             this.dom.style.visibility = "visible";
11192             wrap.show();
11193
11194             arguments.callee.anim = wrap.fxanim(a,
11195                 o,
11196                 'motion',
11197                 .5,
11198                 'easeOut', after);
11199         });
11200         return this;
11201     },
11202     
11203         /**
11204          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
11205          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
11206          * 'hidden') but block elements will still take up space in the document.  The element must be removed
11207          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
11208          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
11209          * Usage:
11210          *<pre><code>
11211 // default: slide the element out to the top
11212 el.slideOut();
11213
11214 // custom: slide the element out to the right with a 2-second duration
11215 el.slideOut('r', { duration: 2 });
11216
11217 // common config options shown with default values
11218 el.slideOut('t', {
11219     easing: 'easeOut',
11220     duration: .5,
11221     remove: false,
11222     useDisplay: false
11223 });
11224 </code></pre>
11225          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
11226          * @param {Object} options (optional) Object literal with any of the Fx config options
11227          * @return {Roo.Element} The Element
11228          */
11229     slideOut : function(anchor, o){
11230         var el = this.getFxEl();
11231         o = o || {};
11232
11233         el.queueFx(o, function(){
11234
11235             anchor = anchor || "t";
11236
11237             // restore values after effect
11238             var r = this.getFxRestore();
11239             
11240             var b = this.getBox();
11241             // fixed size for slide
11242             this.setSize(b);
11243
11244             // wrap if needed
11245             var wrap = this.fxWrap(r.pos, o, "visible");
11246
11247             var st = this.dom.style;
11248             st.visibility = "visible";
11249             st.position = "absolute";
11250
11251             wrap.setSize(b);
11252
11253             var after = function(){
11254                 if(o.useDisplay){
11255                     el.setDisplayed(false);
11256                 }else{
11257                     el.hide();
11258                 }
11259
11260                 el.fxUnwrap(wrap, r.pos, o);
11261
11262                 st.width = r.width;
11263                 st.height = r.height;
11264
11265                 el.afterFx(o);
11266             };
11267
11268             var a, zero = {to: 0};
11269             switch(anchor.toLowerCase()){
11270                 case "t":
11271                     st.left = st.bottom = "0";
11272                     a = {height: zero};
11273                 break;
11274                 case "l":
11275                     st.right = st.top = "0";
11276                     a = {width: zero};
11277                 break;
11278                 case "r":
11279                     st.left = st.top = "0";
11280                     a = {width: zero, points: {to:[b.right, b.y]}};
11281                 break;
11282                 case "b":
11283                     st.left = st.top = "0";
11284                     a = {height: zero, points: {to:[b.x, b.bottom]}};
11285                 break;
11286                 case "tl":
11287                     st.right = st.bottom = "0";
11288                     a = {width: zero, height: zero};
11289                 break;
11290                 case "bl":
11291                     st.right = st.top = "0";
11292                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
11293                 break;
11294                 case "br":
11295                     st.left = st.top = "0";
11296                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
11297                 break;
11298                 case "tr":
11299                     st.left = st.bottom = "0";
11300                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
11301                 break;
11302             }
11303
11304             arguments.callee.anim = wrap.fxanim(a,
11305                 o,
11306                 'motion',
11307                 .5,
11308                 "easeOut", after);
11309         });
11310         return this;
11311     },
11312
11313         /**
11314          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
11315          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
11316          * The element must be removed from the DOM using the 'remove' config option if desired.
11317          * Usage:
11318          *<pre><code>
11319 // default
11320 el.puff();
11321
11322 // common config options shown with default values
11323 el.puff({
11324     easing: 'easeOut',
11325     duration: .5,
11326     remove: false,
11327     useDisplay: false
11328 });
11329 </code></pre>
11330          * @param {Object} options (optional) Object literal with any of the Fx config options
11331          * @return {Roo.Element} The Element
11332          */
11333     puff : function(o){
11334         var el = this.getFxEl();
11335         o = o || {};
11336
11337         el.queueFx(o, function(){
11338             this.clearOpacity();
11339             this.show();
11340
11341             // restore values after effect
11342             var r = this.getFxRestore();
11343             var st = this.dom.style;
11344
11345             var after = function(){
11346                 if(o.useDisplay){
11347                     el.setDisplayed(false);
11348                 }else{
11349                     el.hide();
11350                 }
11351
11352                 el.clearOpacity();
11353
11354                 el.setPositioning(r.pos);
11355                 st.width = r.width;
11356                 st.height = r.height;
11357                 st.fontSize = '';
11358                 el.afterFx(o);
11359             };
11360
11361             var width = this.getWidth();
11362             var height = this.getHeight();
11363
11364             arguments.callee.anim = this.fxanim({
11365                     width : {to: this.adjustWidth(width * 2)},
11366                     height : {to: this.adjustHeight(height * 2)},
11367                     points : {by: [-(width * .5), -(height * .5)]},
11368                     opacity : {to: 0},
11369                     fontSize: {to:200, unit: "%"}
11370                 },
11371                 o,
11372                 'motion',
11373                 .5,
11374                 "easeOut", after);
11375         });
11376         return this;
11377     },
11378
11379         /**
11380          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
11381          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
11382          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
11383          * Usage:
11384          *<pre><code>
11385 // default
11386 el.switchOff();
11387
11388 // all config options shown with default values
11389 el.switchOff({
11390     easing: 'easeIn',
11391     duration: .3,
11392     remove: false,
11393     useDisplay: false
11394 });
11395 </code></pre>
11396          * @param {Object} options (optional) Object literal with any of the Fx config options
11397          * @return {Roo.Element} The Element
11398          */
11399     switchOff : function(o){
11400         var el = this.getFxEl();
11401         o = o || {};
11402
11403         el.queueFx(o, function(){
11404             this.clearOpacity();
11405             this.clip();
11406
11407             // restore values after effect
11408             var r = this.getFxRestore();
11409             var st = this.dom.style;
11410
11411             var after = function(){
11412                 if(o.useDisplay){
11413                     el.setDisplayed(false);
11414                 }else{
11415                     el.hide();
11416                 }
11417
11418                 el.clearOpacity();
11419                 el.setPositioning(r.pos);
11420                 st.width = r.width;
11421                 st.height = r.height;
11422
11423                 el.afterFx(o);
11424             };
11425
11426             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
11427                 this.clearOpacity();
11428                 (function(){
11429                     this.fxanim({
11430                         height:{to:1},
11431                         points:{by:[0, this.getHeight() * .5]}
11432                     }, o, 'motion', 0.3, 'easeIn', after);
11433                 }).defer(100, this);
11434             });
11435         });
11436         return this;
11437     },
11438
11439     /**
11440      * Highlights the Element by setting a color (applies to the background-color by default, but can be
11441      * changed using the "attr" config option) and then fading back to the original color. If no original
11442      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
11443      * Usage:
11444 <pre><code>
11445 // default: highlight background to yellow
11446 el.highlight();
11447
11448 // custom: highlight foreground text to blue for 2 seconds
11449 el.highlight("0000ff", { attr: 'color', duration: 2 });
11450
11451 // common config options shown with default values
11452 el.highlight("ffff9c", {
11453     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
11454     endColor: (current color) or "ffffff",
11455     easing: 'easeIn',
11456     duration: 1
11457 });
11458 </code></pre>
11459      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
11460      * @param {Object} options (optional) Object literal with any of the Fx config options
11461      * @return {Roo.Element} The Element
11462      */ 
11463     highlight : function(color, o){
11464         var el = this.getFxEl();
11465         o = o || {};
11466
11467         el.queueFx(o, function(){
11468             color = color || "ffff9c";
11469             attr = o.attr || "backgroundColor";
11470
11471             this.clearOpacity();
11472             this.show();
11473
11474             var origColor = this.getColor(attr);
11475             var restoreColor = this.dom.style[attr];
11476             endColor = (o.endColor || origColor) || "ffffff";
11477
11478             var after = function(){
11479                 el.dom.style[attr] = restoreColor;
11480                 el.afterFx(o);
11481             };
11482
11483             var a = {};
11484             a[attr] = {from: color, to: endColor};
11485             arguments.callee.anim = this.fxanim(a,
11486                 o,
11487                 'color',
11488                 1,
11489                 'easeIn', after);
11490         });
11491         return this;
11492     },
11493
11494    /**
11495     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
11496     * Usage:
11497 <pre><code>
11498 // default: a single light blue ripple
11499 el.frame();
11500
11501 // custom: 3 red ripples lasting 3 seconds total
11502 el.frame("ff0000", 3, { duration: 3 });
11503
11504 // common config options shown with default values
11505 el.frame("C3DAF9", 1, {
11506     duration: 1 //duration of entire animation (not each individual ripple)
11507     // Note: Easing is not configurable and will be ignored if included
11508 });
11509 </code></pre>
11510     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
11511     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
11512     * @param {Object} options (optional) Object literal with any of the Fx config options
11513     * @return {Roo.Element} The Element
11514     */
11515     frame : function(color, count, o){
11516         var el = this.getFxEl();
11517         o = o || {};
11518
11519         el.queueFx(o, function(){
11520             color = color || "#C3DAF9";
11521             if(color.length == 6){
11522                 color = "#" + color;
11523             }
11524             count = count || 1;
11525             duration = o.duration || 1;
11526             this.show();
11527
11528             var b = this.getBox();
11529             var animFn = function(){
11530                 var proxy = this.createProxy({
11531
11532                      style:{
11533                         visbility:"hidden",
11534                         position:"absolute",
11535                         "z-index":"35000", // yee haw
11536                         border:"0px solid " + color
11537                      }
11538                   });
11539                 var scale = Roo.isBorderBox ? 2 : 1;
11540                 proxy.animate({
11541                     top:{from:b.y, to:b.y - 20},
11542                     left:{from:b.x, to:b.x - 20},
11543                     borderWidth:{from:0, to:10},
11544                     opacity:{from:1, to:0},
11545                     height:{from:b.height, to:(b.height + (20*scale))},
11546                     width:{from:b.width, to:(b.width + (20*scale))}
11547                 }, duration, function(){
11548                     proxy.remove();
11549                 });
11550                 if(--count > 0){
11551                      animFn.defer((duration/2)*1000, this);
11552                 }else{
11553                     el.afterFx(o);
11554                 }
11555             };
11556             animFn.call(this);
11557         });
11558         return this;
11559     },
11560
11561    /**
11562     * Creates a pause before any subsequent queued effects begin.  If there are
11563     * no effects queued after the pause it will have no effect.
11564     * Usage:
11565 <pre><code>
11566 el.pause(1);
11567 </code></pre>
11568     * @param {Number} seconds The length of time to pause (in seconds)
11569     * @return {Roo.Element} The Element
11570     */
11571     pause : function(seconds){
11572         var el = this.getFxEl();
11573         var o = {};
11574
11575         el.queueFx(o, function(){
11576             setTimeout(function(){
11577                 el.afterFx(o);
11578             }, seconds * 1000);
11579         });
11580         return this;
11581     },
11582
11583    /**
11584     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
11585     * using the "endOpacity" config option.
11586     * Usage:
11587 <pre><code>
11588 // default: fade in from opacity 0 to 100%
11589 el.fadeIn();
11590
11591 // custom: fade in from opacity 0 to 75% over 2 seconds
11592 el.fadeIn({ endOpacity: .75, duration: 2});
11593
11594 // common config options shown with default values
11595 el.fadeIn({
11596     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
11597     easing: 'easeOut',
11598     duration: .5
11599 });
11600 </code></pre>
11601     * @param {Object} options (optional) Object literal with any of the Fx config options
11602     * @return {Roo.Element} The Element
11603     */
11604     fadeIn : function(o){
11605         var el = this.getFxEl();
11606         o = o || {};
11607         el.queueFx(o, function(){
11608             this.setOpacity(0);
11609             this.fixDisplay();
11610             this.dom.style.visibility = 'visible';
11611             var to = o.endOpacity || 1;
11612             arguments.callee.anim = this.fxanim({opacity:{to:to}},
11613                 o, null, .5, "easeOut", function(){
11614                 if(to == 1){
11615                     this.clearOpacity();
11616                 }
11617                 el.afterFx(o);
11618             });
11619         });
11620         return this;
11621     },
11622
11623    /**
11624     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
11625     * using the "endOpacity" config option.
11626     * Usage:
11627 <pre><code>
11628 // default: fade out from the element's current opacity to 0
11629 el.fadeOut();
11630
11631 // custom: fade out from the element's current opacity to 25% over 2 seconds
11632 el.fadeOut({ endOpacity: .25, duration: 2});
11633
11634 // common config options shown with default values
11635 el.fadeOut({
11636     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
11637     easing: 'easeOut',
11638     duration: .5
11639     remove: false,
11640     useDisplay: false
11641 });
11642 </code></pre>
11643     * @param {Object} options (optional) Object literal with any of the Fx config options
11644     * @return {Roo.Element} The Element
11645     */
11646     fadeOut : function(o){
11647         var el = this.getFxEl();
11648         o = o || {};
11649         el.queueFx(o, function(){
11650             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
11651                 o, null, .5, "easeOut", function(){
11652                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
11653                      this.dom.style.display = "none";
11654                 }else{
11655                      this.dom.style.visibility = "hidden";
11656                 }
11657                 this.clearOpacity();
11658                 el.afterFx(o);
11659             });
11660         });
11661         return this;
11662     },
11663
11664    /**
11665     * Animates the transition of an element's dimensions from a starting height/width
11666     * to an ending height/width.
11667     * Usage:
11668 <pre><code>
11669 // change height and width to 100x100 pixels
11670 el.scale(100, 100);
11671
11672 // common config options shown with default values.  The height and width will default to
11673 // the element's existing values if passed as null.
11674 el.scale(
11675     [element's width],
11676     [element's height], {
11677     easing: 'easeOut',
11678     duration: .35
11679 });
11680 </code></pre>
11681     * @param {Number} width  The new width (pass undefined to keep the original width)
11682     * @param {Number} height  The new height (pass undefined to keep the original height)
11683     * @param {Object} options (optional) Object literal with any of the Fx config options
11684     * @return {Roo.Element} The Element
11685     */
11686     scale : function(w, h, o){
11687         this.shift(Roo.apply({}, o, {
11688             width: w,
11689             height: h
11690         }));
11691         return this;
11692     },
11693
11694    /**
11695     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
11696     * Any of these properties not specified in the config object will not be changed.  This effect 
11697     * requires that at least one new dimension, position or opacity setting must be passed in on
11698     * the config object in order for the function to have any effect.
11699     * Usage:
11700 <pre><code>
11701 // slide the element horizontally to x position 200 while changing the height and opacity
11702 el.shift({ x: 200, height: 50, opacity: .8 });
11703
11704 // common config options shown with default values.
11705 el.shift({
11706     width: [element's width],
11707     height: [element's height],
11708     x: [element's x position],
11709     y: [element's y position],
11710     opacity: [element's opacity],
11711     easing: 'easeOut',
11712     duration: .35
11713 });
11714 </code></pre>
11715     * @param {Object} options  Object literal with any of the Fx config options
11716     * @return {Roo.Element} The Element
11717     */
11718     shift : function(o){
11719         var el = this.getFxEl();
11720         o = o || {};
11721         el.queueFx(o, function(){
11722             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
11723             if(w !== undefined){
11724                 a.width = {to: this.adjustWidth(w)};
11725             }
11726             if(h !== undefined){
11727                 a.height = {to: this.adjustHeight(h)};
11728             }
11729             if(x !== undefined || y !== undefined){
11730                 a.points = {to: [
11731                     x !== undefined ? x : this.getX(),
11732                     y !== undefined ? y : this.getY()
11733                 ]};
11734             }
11735             if(op !== undefined){
11736                 a.opacity = {to: op};
11737             }
11738             if(o.xy !== undefined){
11739                 a.points = {to: o.xy};
11740             }
11741             arguments.callee.anim = this.fxanim(a,
11742                 o, 'motion', .35, "easeOut", function(){
11743                 el.afterFx(o);
11744             });
11745         });
11746         return this;
11747     },
11748
11749         /**
11750          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
11751          * ending point of the effect.
11752          * Usage:
11753          *<pre><code>
11754 // default: slide the element downward while fading out
11755 el.ghost();
11756
11757 // custom: slide the element out to the right with a 2-second duration
11758 el.ghost('r', { duration: 2 });
11759
11760 // common config options shown with default values
11761 el.ghost('b', {
11762     easing: 'easeOut',
11763     duration: .5
11764     remove: false,
11765     useDisplay: false
11766 });
11767 </code></pre>
11768          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
11769          * @param {Object} options (optional) Object literal with any of the Fx config options
11770          * @return {Roo.Element} The Element
11771          */
11772     ghost : function(anchor, o){
11773         var el = this.getFxEl();
11774         o = o || {};
11775
11776         el.queueFx(o, function(){
11777             anchor = anchor || "b";
11778
11779             // restore values after effect
11780             var r = this.getFxRestore();
11781             var w = this.getWidth(),
11782                 h = this.getHeight();
11783
11784             var st = this.dom.style;
11785
11786             var after = function(){
11787                 if(o.useDisplay){
11788                     el.setDisplayed(false);
11789                 }else{
11790                     el.hide();
11791                 }
11792
11793                 el.clearOpacity();
11794                 el.setPositioning(r.pos);
11795                 st.width = r.width;
11796                 st.height = r.height;
11797
11798                 el.afterFx(o);
11799             };
11800
11801             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
11802             switch(anchor.toLowerCase()){
11803                 case "t":
11804                     pt.by = [0, -h];
11805                 break;
11806                 case "l":
11807                     pt.by = [-w, 0];
11808                 break;
11809                 case "r":
11810                     pt.by = [w, 0];
11811                 break;
11812                 case "b":
11813                     pt.by = [0, h];
11814                 break;
11815                 case "tl":
11816                     pt.by = [-w, -h];
11817                 break;
11818                 case "bl":
11819                     pt.by = [-w, h];
11820                 break;
11821                 case "br":
11822                     pt.by = [w, h];
11823                 break;
11824                 case "tr":
11825                     pt.by = [w, -h];
11826                 break;
11827             }
11828
11829             arguments.callee.anim = this.fxanim(a,
11830                 o,
11831                 'motion',
11832                 .5,
11833                 "easeOut", after);
11834         });
11835         return this;
11836     },
11837
11838         /**
11839          * Ensures that all effects queued after syncFx is called on the element are
11840          * run concurrently.  This is the opposite of {@link #sequenceFx}.
11841          * @return {Roo.Element} The Element
11842          */
11843     syncFx : function(){
11844         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
11845             block : false,
11846             concurrent : true,
11847             stopFx : false
11848         });
11849         return this;
11850     },
11851
11852         /**
11853          * Ensures that all effects queued after sequenceFx is called on the element are
11854          * run in sequence.  This is the opposite of {@link #syncFx}.
11855          * @return {Roo.Element} The Element
11856          */
11857     sequenceFx : function(){
11858         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
11859             block : false,
11860             concurrent : false,
11861             stopFx : false
11862         });
11863         return this;
11864     },
11865
11866         /* @private */
11867     nextFx : function(){
11868         var ef = this.fxQueue[0];
11869         if(ef){
11870             ef.call(this);
11871         }
11872     },
11873
11874         /**
11875          * Returns true if the element has any effects actively running or queued, else returns false.
11876          * @return {Boolean} True if element has active effects, else false
11877          */
11878     hasActiveFx : function(){
11879         return this.fxQueue && this.fxQueue[0];
11880     },
11881
11882         /**
11883          * Stops any running effects and clears the element's internal effects queue if it contains
11884          * any additional effects that haven't started yet.
11885          * @return {Roo.Element} The Element
11886          */
11887     stopFx : function(){
11888         if(this.hasActiveFx()){
11889             var cur = this.fxQueue[0];
11890             if(cur && cur.anim && cur.anim.isAnimated()){
11891                 this.fxQueue = [cur]; // clear out others
11892                 cur.anim.stop(true);
11893             }
11894         }
11895         return this;
11896     },
11897
11898         /* @private */
11899     beforeFx : function(o){
11900         if(this.hasActiveFx() && !o.concurrent){
11901            if(o.stopFx){
11902                this.stopFx();
11903                return true;
11904            }
11905            return false;
11906         }
11907         return true;
11908     },
11909
11910         /**
11911          * Returns true if the element is currently blocking so that no other effect can be queued
11912          * until this effect is finished, else returns false if blocking is not set.  This is commonly
11913          * used to ensure that an effect initiated by a user action runs to completion prior to the
11914          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
11915          * @return {Boolean} True if blocking, else false
11916          */
11917     hasFxBlock : function(){
11918         var q = this.fxQueue;
11919         return q && q[0] && q[0].block;
11920     },
11921
11922         /* @private */
11923     queueFx : function(o, fn){
11924         if(!this.fxQueue){
11925             this.fxQueue = [];
11926         }
11927         if(!this.hasFxBlock()){
11928             Roo.applyIf(o, this.fxDefaults);
11929             if(!o.concurrent){
11930                 var run = this.beforeFx(o);
11931                 fn.block = o.block;
11932                 this.fxQueue.push(fn);
11933                 if(run){
11934                     this.nextFx();
11935                 }
11936             }else{
11937                 fn.call(this);
11938             }
11939         }
11940         return this;
11941     },
11942
11943         /* @private */
11944     fxWrap : function(pos, o, vis){
11945         var wrap;
11946         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
11947             var wrapXY;
11948             if(o.fixPosition){
11949                 wrapXY = this.getXY();
11950             }
11951             var div = document.createElement("div");
11952             div.style.visibility = vis;
11953             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
11954             wrap.setPositioning(pos);
11955             if(wrap.getStyle("position") == "static"){
11956                 wrap.position("relative");
11957             }
11958             this.clearPositioning('auto');
11959             wrap.clip();
11960             wrap.dom.appendChild(this.dom);
11961             if(wrapXY){
11962                 wrap.setXY(wrapXY);
11963             }
11964         }
11965         return wrap;
11966     },
11967
11968         /* @private */
11969     fxUnwrap : function(wrap, pos, o){
11970         this.clearPositioning();
11971         this.setPositioning(pos);
11972         if(!o.wrap){
11973             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
11974             wrap.remove();
11975         }
11976     },
11977
11978         /* @private */
11979     getFxRestore : function(){
11980         var st = this.dom.style;
11981         return {pos: this.getPositioning(), width: st.width, height : st.height};
11982     },
11983
11984         /* @private */
11985     afterFx : function(o){
11986         if(o.afterStyle){
11987             this.applyStyles(o.afterStyle);
11988         }
11989         if(o.afterCls){
11990             this.addClass(o.afterCls);
11991         }
11992         if(o.remove === true){
11993             this.remove();
11994         }
11995         Roo.callback(o.callback, o.scope, [this]);
11996         if(!o.concurrent){
11997             this.fxQueue.shift();
11998             this.nextFx();
11999         }
12000     },
12001
12002         /* @private */
12003     getFxEl : function(){ // support for composite element fx
12004         return Roo.get(this.dom);
12005     },
12006
12007         /* @private */
12008     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
12009         animType = animType || 'run';
12010         opt = opt || {};
12011         var anim = Roo.lib.Anim[animType](
12012             this.dom, args,
12013             (opt.duration || defaultDur) || .35,
12014             (opt.easing || defaultEase) || 'easeOut',
12015             function(){
12016                 Roo.callback(cb, this);
12017             },
12018             this
12019         );
12020         opt.anim = anim;
12021         return anim;
12022     }
12023 };
12024
12025 // backwords compat
12026 Roo.Fx.resize = Roo.Fx.scale;
12027
12028 //When included, Roo.Fx is automatically applied to Element so that all basic
12029 //effects are available directly via the Element API
12030 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
12031  * Based on:
12032  * Ext JS Library 1.1.1
12033  * Copyright(c) 2006-2007, Ext JS, LLC.
12034  *
12035  * Originally Released Under LGPL - original licence link has changed is not relivant.
12036  *
12037  * Fork - LGPL
12038  * <script type="text/javascript">
12039  */
12040
12041
12042 /**
12043  * @class Roo.CompositeElement
12044  * Standard composite class. Creates a Roo.Element for every element in the collection.
12045  * <br><br>
12046  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
12047  * actions will be performed on all the elements in this collection.</b>
12048  * <br><br>
12049  * All methods return <i>this</i> and can be chained.
12050  <pre><code>
12051  var els = Roo.select("#some-el div.some-class", true);
12052  // or select directly from an existing element
12053  var el = Roo.get('some-el');
12054  el.select('div.some-class', true);
12055
12056  els.setWidth(100); // all elements become 100 width
12057  els.hide(true); // all elements fade out and hide
12058  // or
12059  els.setWidth(100).hide(true);
12060  </code></pre>
12061  */
12062 Roo.CompositeElement = function(els){
12063     this.elements = [];
12064     this.addElements(els);
12065 };
12066 Roo.CompositeElement.prototype = {
12067     isComposite: true,
12068     addElements : function(els){
12069         if(!els) {
12070             return this;
12071         }
12072         if(typeof els == "string"){
12073             els = Roo.Element.selectorFunction(els);
12074         }
12075         var yels = this.elements;
12076         var index = yels.length-1;
12077         for(var i = 0, len = els.length; i < len; i++) {
12078                 yels[++index] = Roo.get(els[i]);
12079         }
12080         return this;
12081     },
12082
12083     /**
12084     * Clears this composite and adds the elements returned by the passed selector.
12085     * @param {String/Array} els A string CSS selector, an array of elements or an element
12086     * @return {CompositeElement} this
12087     */
12088     fill : function(els){
12089         this.elements = [];
12090         this.add(els);
12091         return this;
12092     },
12093
12094     /**
12095     * Filters this composite to only elements that match the passed selector.
12096     * @param {String} selector A string CSS selector
12097     * @param {Boolean} inverse return inverse filter (not matches)
12098     * @return {CompositeElement} this
12099     */
12100     filter : function(selector, inverse){
12101         var els = [];
12102         inverse = inverse || false;
12103         this.each(function(el){
12104             var match = inverse ? !el.is(selector) : el.is(selector);
12105             if(match){
12106                 els[els.length] = el.dom;
12107             }
12108         });
12109         this.fill(els);
12110         return this;
12111     },
12112
12113     invoke : function(fn, args){
12114         var els = this.elements;
12115         for(var i = 0, len = els.length; i < len; i++) {
12116                 Roo.Element.prototype[fn].apply(els[i], args);
12117         }
12118         return this;
12119     },
12120     /**
12121     * Adds elements to this composite.
12122     * @param {String/Array} els A string CSS selector, an array of elements or an element
12123     * @return {CompositeElement} this
12124     */
12125     add : function(els){
12126         if(typeof els == "string"){
12127             this.addElements(Roo.Element.selectorFunction(els));
12128         }else if(els.length !== undefined){
12129             this.addElements(els);
12130         }else{
12131             this.addElements([els]);
12132         }
12133         return this;
12134     },
12135     /**
12136     * Calls the passed function passing (el, this, index) for each element in this composite.
12137     * @param {Function} fn The function to call
12138     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
12139     * @return {CompositeElement} this
12140     */
12141     each : function(fn, scope){
12142         var els = this.elements;
12143         for(var i = 0, len = els.length; i < len; i++){
12144             if(fn.call(scope || els[i], els[i], this, i) === false) {
12145                 break;
12146             }
12147         }
12148         return this;
12149     },
12150
12151     /**
12152      * Returns the Element object at the specified index
12153      * @param {Number} index
12154      * @return {Roo.Element}
12155      */
12156     item : function(index){
12157         return this.elements[index] || null;
12158     },
12159
12160     /**
12161      * Returns the first Element
12162      * @return {Roo.Element}
12163      */
12164     first : function(){
12165         return this.item(0);
12166     },
12167
12168     /**
12169      * Returns the last Element
12170      * @return {Roo.Element}
12171      */
12172     last : function(){
12173         return this.item(this.elements.length-1);
12174     },
12175
12176     /**
12177      * Returns the number of elements in this composite
12178      * @return Number
12179      */
12180     getCount : function(){
12181         return this.elements.length;
12182     },
12183
12184     /**
12185      * Returns true if this composite contains the passed element
12186      * @return Boolean
12187      */
12188     contains : function(el){
12189         return this.indexOf(el) !== -1;
12190     },
12191
12192     /**
12193      * Returns true if this composite contains the passed element
12194      * @return Boolean
12195      */
12196     indexOf : function(el){
12197         return this.elements.indexOf(Roo.get(el));
12198     },
12199
12200
12201     /**
12202     * Removes the specified element(s).
12203     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
12204     * or an array of any of those.
12205     * @param {Boolean} removeDom (optional) True to also remove the element from the document
12206     * @return {CompositeElement} this
12207     */
12208     removeElement : function(el, removeDom){
12209         if(el instanceof Array){
12210             for(var i = 0, len = el.length; i < len; i++){
12211                 this.removeElement(el[i]);
12212             }
12213             return this;
12214         }
12215         var index = typeof el == 'number' ? el : this.indexOf(el);
12216         if(index !== -1){
12217             if(removeDom){
12218                 var d = this.elements[index];
12219                 if(d.dom){
12220                     d.remove();
12221                 }else{
12222                     d.parentNode.removeChild(d);
12223                 }
12224             }
12225             this.elements.splice(index, 1);
12226         }
12227         return this;
12228     },
12229
12230     /**
12231     * Replaces the specified element with the passed element.
12232     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
12233     * to replace.
12234     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
12235     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
12236     * @return {CompositeElement} this
12237     */
12238     replaceElement : function(el, replacement, domReplace){
12239         var index = typeof el == 'number' ? el : this.indexOf(el);
12240         if(index !== -1){
12241             if(domReplace){
12242                 this.elements[index].replaceWith(replacement);
12243             }else{
12244                 this.elements.splice(index, 1, Roo.get(replacement))
12245             }
12246         }
12247         return this;
12248     },
12249
12250     /**
12251      * Removes all elements.
12252      */
12253     clear : function(){
12254         this.elements = [];
12255     }
12256 };
12257 (function(){
12258     Roo.CompositeElement.createCall = function(proto, fnName){
12259         if(!proto[fnName]){
12260             proto[fnName] = function(){
12261                 return this.invoke(fnName, arguments);
12262             };
12263         }
12264     };
12265     for(var fnName in Roo.Element.prototype){
12266         if(typeof Roo.Element.prototype[fnName] == "function"){
12267             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
12268         }
12269     };
12270 })();
12271 /*
12272  * Based on:
12273  * Ext JS Library 1.1.1
12274  * Copyright(c) 2006-2007, Ext JS, LLC.
12275  *
12276  * Originally Released Under LGPL - original licence link has changed is not relivant.
12277  *
12278  * Fork - LGPL
12279  * <script type="text/javascript">
12280  */
12281
12282 /**
12283  * @class Roo.CompositeElementLite
12284  * @extends Roo.CompositeElement
12285  * Flyweight composite class. Reuses the same Roo.Element for element operations.
12286  <pre><code>
12287  var els = Roo.select("#some-el div.some-class");
12288  // or select directly from an existing element
12289  var el = Roo.get('some-el');
12290  el.select('div.some-class');
12291
12292  els.setWidth(100); // all elements become 100 width
12293  els.hide(true); // all elements fade out and hide
12294  // or
12295  els.setWidth(100).hide(true);
12296  </code></pre><br><br>
12297  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
12298  * actions will be performed on all the elements in this collection.</b>
12299  */
12300 Roo.CompositeElementLite = function(els){
12301     Roo.CompositeElementLite.superclass.constructor.call(this, els);
12302     this.el = new Roo.Element.Flyweight();
12303 };
12304 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
12305     addElements : function(els){
12306         if(els){
12307             if(els instanceof Array){
12308                 this.elements = this.elements.concat(els);
12309             }else{
12310                 var yels = this.elements;
12311                 var index = yels.length-1;
12312                 for(var i = 0, len = els.length; i < len; i++) {
12313                     yels[++index] = els[i];
12314                 }
12315             }
12316         }
12317         return this;
12318     },
12319     invoke : function(fn, args){
12320         var els = this.elements;
12321         var el = this.el;
12322         for(var i = 0, len = els.length; i < len; i++) {
12323             el.dom = els[i];
12324                 Roo.Element.prototype[fn].apply(el, args);
12325         }
12326         return this;
12327     },
12328     /**
12329      * Returns a flyweight Element of the dom element object at the specified index
12330      * @param {Number} index
12331      * @return {Roo.Element}
12332      */
12333     item : function(index){
12334         if(!this.elements[index]){
12335             return null;
12336         }
12337         this.el.dom = this.elements[index];
12338         return this.el;
12339     },
12340
12341     // fixes scope with flyweight
12342     addListener : function(eventName, handler, scope, opt){
12343         var els = this.elements;
12344         for(var i = 0, len = els.length; i < len; i++) {
12345             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
12346         }
12347         return this;
12348     },
12349
12350     /**
12351     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
12352     * passed is the flyweight (shared) Roo.Element instance, so if you require a
12353     * a reference to the dom node, use el.dom.</b>
12354     * @param {Function} fn The function to call
12355     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
12356     * @return {CompositeElement} this
12357     */
12358     each : function(fn, scope){
12359         var els = this.elements;
12360         var el = this.el;
12361         for(var i = 0, len = els.length; i < len; i++){
12362             el.dom = els[i];
12363                 if(fn.call(scope || el, el, this, i) === false){
12364                 break;
12365             }
12366         }
12367         return this;
12368     },
12369
12370     indexOf : function(el){
12371         return this.elements.indexOf(Roo.getDom(el));
12372     },
12373
12374     replaceElement : function(el, replacement, domReplace){
12375         var index = typeof el == 'number' ? el : this.indexOf(el);
12376         if(index !== -1){
12377             replacement = Roo.getDom(replacement);
12378             if(domReplace){
12379                 var d = this.elements[index];
12380                 d.parentNode.insertBefore(replacement, d);
12381                 d.parentNode.removeChild(d);
12382             }
12383             this.elements.splice(index, 1, replacement);
12384         }
12385         return this;
12386     }
12387 });
12388 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
12389
12390 /*
12391  * Based on:
12392  * Ext JS Library 1.1.1
12393  * Copyright(c) 2006-2007, Ext JS, LLC.
12394  *
12395  * Originally Released Under LGPL - original licence link has changed is not relivant.
12396  *
12397  * Fork - LGPL
12398  * <script type="text/javascript">
12399  */
12400
12401  
12402
12403 /**
12404  * @class Roo.data.Connection
12405  * @extends Roo.util.Observable
12406  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
12407  * either to a configured URL, or to a URL specified at request time. 
12408  * 
12409  * Requests made by this class are asynchronous, and will return immediately. No data from
12410  * the server will be available to the statement immediately following the {@link #request} call.
12411  * To process returned data, use a callback in the request options object, or an event listener.
12412  * 
12413  * Note: If you are doing a file upload, you will not get a normal response object sent back to
12414  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
12415  * The response object is created using the innerHTML of the IFRAME's document as the responseText
12416  * property and, if present, the IFRAME's XML document as the responseXML property.
12417  * 
12418  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
12419  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
12420  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
12421  * standard DOM methods.
12422  * @constructor
12423  * @param {Object} config a configuration object.
12424  */
12425 Roo.data.Connection = function(config){
12426     Roo.apply(this, config);
12427     this.addEvents({
12428         /**
12429          * @event beforerequest
12430          * Fires before a network request is made to retrieve a data object.
12431          * @param {Connection} conn This Connection object.
12432          * @param {Object} options The options config object passed to the {@link #request} method.
12433          */
12434         "beforerequest" : true,
12435         /**
12436          * @event requestcomplete
12437          * Fires if the request was successfully completed.
12438          * @param {Connection} conn This Connection object.
12439          * @param {Object} response The XHR object containing the response data.
12440          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
12441          * @param {Object} options The options config object passed to the {@link #request} method.
12442          */
12443         "requestcomplete" : true,
12444         /**
12445          * @event requestexception
12446          * Fires if an error HTTP status was returned from the server.
12447          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
12448          * @param {Connection} conn This Connection object.
12449          * @param {Object} response The XHR object containing the response data.
12450          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
12451          * @param {Object} options The options config object passed to the {@link #request} method.
12452          */
12453         "requestexception" : true
12454     });
12455     Roo.data.Connection.superclass.constructor.call(this);
12456 };
12457
12458 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
12459     /**
12460      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12461      */
12462     /**
12463      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12464      * extra parameters to each request made by this object. (defaults to undefined)
12465      */
12466     /**
12467      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12468      *  to each request made by this object. (defaults to undefined)
12469      */
12470     /**
12471      * @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)
12472      */
12473     /**
12474      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12475      */
12476     timeout : 30000,
12477     /**
12478      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12479      * @type Boolean
12480      */
12481     autoAbort:false,
12482
12483     /**
12484      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12485      * @type Boolean
12486      */
12487     disableCaching: true,
12488
12489     /**
12490      * Sends an HTTP request to a remote server.
12491      * @param {Object} options An object which may contain the following properties:<ul>
12492      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
12493      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
12494      * request, a url encoded string or a function to call to get either.</li>
12495      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
12496      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
12497      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
12498      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
12499      * <li>options {Object} The parameter to the request call.</li>
12500      * <li>success {Boolean} True if the request succeeded.</li>
12501      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
12502      * </ul></li>
12503      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
12504      * The callback is passed the following parameters:<ul>
12505      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
12506      * <li>options {Object} The parameter to the request call.</li>
12507      * </ul></li>
12508      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
12509      * The callback is passed the following parameters:<ul>
12510      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
12511      * <li>options {Object} The parameter to the request call.</li>
12512      * </ul></li>
12513      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
12514      * for the callback function. Defaults to the browser window.</li>
12515      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
12516      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
12517      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
12518      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
12519      * params for the post data. Any params will be appended to the URL.</li>
12520      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
12521      * </ul>
12522      * @return {Number} transactionId
12523      */
12524     request : function(o){
12525         if(this.fireEvent("beforerequest", this, o) !== false){
12526             var p = o.params;
12527
12528             if(typeof p == "function"){
12529                 p = p.call(o.scope||window, o);
12530             }
12531             if(typeof p == "object"){
12532                 p = Roo.urlEncode(o.params);
12533             }
12534             if(this.extraParams){
12535                 var extras = Roo.urlEncode(this.extraParams);
12536                 p = p ? (p + '&' + extras) : extras;
12537             }
12538
12539             var url = o.url || this.url;
12540             if(typeof url == 'function'){
12541                 url = url.call(o.scope||window, o);
12542             }
12543
12544             if(o.form){
12545                 var form = Roo.getDom(o.form);
12546                 url = url || form.action;
12547
12548                 var enctype = form.getAttribute("enctype");
12549                 
12550                 if (o.formData) {
12551                     return this.doFormDataUpload(o, url);
12552                 }
12553                 
12554                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
12555                     return this.doFormUpload(o, p, url);
12556                 }
12557                 var f = Roo.lib.Ajax.serializeForm(form);
12558                 p = p ? (p + '&' + f) : f;
12559             }
12560             
12561             if (!o.form && o.formData) {
12562                 o.formData = o.formData === true ? new FormData() : o.formData;
12563                 for (var k in o.params) {
12564                     o.formData.append(k,o.params[k]);
12565                 }
12566                     
12567                 return this.doFormDataUpload(o, url);
12568             }
12569             
12570
12571             var hs = o.headers;
12572             if(this.defaultHeaders){
12573                 hs = Roo.apply(hs || {}, this.defaultHeaders);
12574                 if(!o.headers){
12575                     o.headers = hs;
12576                 }
12577             }
12578
12579             var cb = {
12580                 success: this.handleResponse,
12581                 failure: this.handleFailure,
12582                 scope: this,
12583                 argument: {options: o},
12584                 timeout : o.timeout || this.timeout
12585             };
12586
12587             var method = o.method||this.method||(p ? "POST" : "GET");
12588
12589             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
12590                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
12591             }
12592
12593             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
12594                 if(o.autoAbort){
12595                     this.abort();
12596                 }
12597             }else if(this.autoAbort !== false){
12598                 this.abort();
12599             }
12600
12601             if((method == 'GET' && p) || o.xmlData){
12602                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
12603                 p = '';
12604             }
12605             Roo.lib.Ajax.useDefaultHeader = typeof(o.headers) == 'undefined' || typeof(o.headers['Content-Type']) == 'undefined';
12606             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
12607             Roo.lib.Ajax.useDefaultHeader == true;
12608             return this.transId;
12609         }else{
12610             Roo.callback(o.callback, o.scope, [o, null, null]);
12611             return null;
12612         }
12613     },
12614
12615     /**
12616      * Determine whether this object has a request outstanding.
12617      * @param {Number} transactionId (Optional) defaults to the last transaction
12618      * @return {Boolean} True if there is an outstanding request.
12619      */
12620     isLoading : function(transId){
12621         if(transId){
12622             return Roo.lib.Ajax.isCallInProgress(transId);
12623         }else{
12624             return this.transId ? true : false;
12625         }
12626     },
12627
12628     /**
12629      * Aborts any outstanding request.
12630      * @param {Number} transactionId (Optional) defaults to the last transaction
12631      */
12632     abort : function(transId){
12633         if(transId || this.isLoading()){
12634             Roo.lib.Ajax.abort(transId || this.transId);
12635         }
12636     },
12637
12638     // private
12639     handleResponse : function(response){
12640         this.transId = false;
12641         var options = response.argument.options;
12642         response.argument = options ? options.argument : null;
12643         this.fireEvent("requestcomplete", this, response, options);
12644         Roo.callback(options.success, options.scope, [response, options]);
12645         Roo.callback(options.callback, options.scope, [options, true, response]);
12646     },
12647
12648     // private
12649     handleFailure : function(response, e){
12650         this.transId = false;
12651         var options = response.argument.options;
12652         response.argument = options ? options.argument : null;
12653         this.fireEvent("requestexception", this, response, options, e);
12654         Roo.callback(options.failure, options.scope, [response, options]);
12655         Roo.callback(options.callback, options.scope, [options, false, response]);
12656     },
12657
12658     // private
12659     doFormUpload : function(o, ps, url){
12660         var id = Roo.id();
12661         var frame = document.createElement('iframe');
12662         frame.id = id;
12663         frame.name = id;
12664         frame.className = 'x-hidden';
12665         if(Roo.isIE){
12666             frame.src = Roo.SSL_SECURE_URL;
12667         }
12668         document.body.appendChild(frame);
12669
12670         if(Roo.isIE){
12671            document.frames[id].name = id;
12672         }
12673
12674         var form = Roo.getDom(o.form);
12675         form.target = id;
12676         form.method = 'POST';
12677         form.enctype = form.encoding = 'multipart/form-data';
12678         if(url){
12679             form.action = url;
12680         }
12681
12682         var hiddens, hd;
12683         if(ps){ // add dynamic params
12684             hiddens = [];
12685             ps = Roo.urlDecode(ps, false);
12686             for(var k in ps){
12687                 if(ps.hasOwnProperty(k)){
12688                     hd = document.createElement('input');
12689                     hd.type = 'hidden';
12690                     hd.name = k;
12691                     hd.value = ps[k];
12692                     form.appendChild(hd);
12693                     hiddens.push(hd);
12694                 }
12695             }
12696         }
12697
12698         function cb(){
12699             var r = {  // bogus response object
12700                 responseText : '',
12701                 responseXML : null
12702             };
12703
12704             r.argument = o ? o.argument : null;
12705
12706             try { //
12707                 var doc;
12708                 if(Roo.isIE){
12709                     doc = frame.contentWindow.document;
12710                 }else {
12711                     doc = (frame.contentDocument || window.frames[id].document);
12712                 }
12713                 if(doc && doc.body){
12714                     r.responseText = doc.body.innerHTML;
12715                 }
12716                 if(doc && doc.XMLDocument){
12717                     r.responseXML = doc.XMLDocument;
12718                 }else {
12719                     r.responseXML = doc;
12720                 }
12721             }
12722             catch(e) {
12723                 // ignore
12724             }
12725
12726             Roo.EventManager.removeListener(frame, 'load', cb, this);
12727
12728             this.fireEvent("requestcomplete", this, r, o);
12729             Roo.callback(o.success, o.scope, [r, o]);
12730             Roo.callback(o.callback, o.scope, [o, true, r]);
12731
12732             setTimeout(function(){document.body.removeChild(frame);}, 100);
12733         }
12734
12735         Roo.EventManager.on(frame, 'load', cb, this);
12736         form.submit();
12737
12738         if(hiddens){ // remove dynamic params
12739             for(var i = 0, len = hiddens.length; i < len; i++){
12740                 form.removeChild(hiddens[i]);
12741             }
12742         }
12743     },
12744     // this is a 'formdata version???'
12745     
12746     
12747     doFormDataUpload : function(o,  url)
12748     {
12749         var formData;
12750         if (o.form) {
12751             var form =  Roo.getDom(o.form);
12752             form.enctype = form.encoding = 'multipart/form-data';
12753             formData = o.formData === true ? new FormData(form) : o.formData;
12754         } else {
12755             formData = o.formData === true ? new FormData() : o.formData;
12756         }
12757         
12758       
12759         var cb = {
12760             success: this.handleResponse,
12761             failure: this.handleFailure,
12762             scope: this,
12763             argument: {options: o},
12764             timeout : o.timeout || this.timeout
12765         };
12766  
12767         if(typeof o.autoAbort == 'boolean'){ // options gets top priority
12768             if(o.autoAbort){
12769                 this.abort();
12770             }
12771         }else if(this.autoAbort !== false){
12772             this.abort();
12773         }
12774
12775         //Roo.lib.Ajax.defaultPostHeader = null;
12776         Roo.lib.Ajax.useDefaultHeader = false;
12777         this.transId = Roo.lib.Ajax.request( "POST", url, cb,  formData, o);
12778         Roo.lib.Ajax.useDefaultHeader = true;
12779  
12780          
12781     }
12782     
12783 });
12784 /*
12785  * Based on:
12786  * Ext JS Library 1.1.1
12787  * Copyright(c) 2006-2007, Ext JS, LLC.
12788  *
12789  * Originally Released Under LGPL - original licence link has changed is not relivant.
12790  *
12791  * Fork - LGPL
12792  * <script type="text/javascript">
12793  */
12794  
12795 /**
12796  * Global Ajax request class.
12797  * 
12798  * @class Roo.Ajax
12799  * @extends Roo.data.Connection
12800  * @static
12801  * 
12802  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
12803  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
12804  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
12805  * @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)
12806  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12807  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
12808  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
12809  */
12810 Roo.Ajax = new Roo.data.Connection({
12811     // fix up the docs
12812     /**
12813      * @scope Roo.Ajax
12814      * @type {Boolear} 
12815      */
12816     autoAbort : false,
12817
12818     /**
12819      * Serialize the passed form into a url encoded string
12820      * @scope Roo.Ajax
12821      * @param {String/HTMLElement} form
12822      * @return {String}
12823      */
12824     serializeForm : function(form){
12825         return Roo.lib.Ajax.serializeForm(form);
12826     }
12827 });/*
12828  * Based on:
12829  * Ext JS Library 1.1.1
12830  * Copyright(c) 2006-2007, Ext JS, LLC.
12831  *
12832  * Originally Released Under LGPL - original licence link has changed is not relivant.
12833  *
12834  * Fork - LGPL
12835  * <script type="text/javascript">
12836  */
12837
12838  
12839 /**
12840  * @class Roo.UpdateManager
12841  * @extends Roo.util.Observable
12842  * Provides AJAX-style update for Element object.<br><br>
12843  * Usage:<br>
12844  * <pre><code>
12845  * // Get it from a Roo.Element object
12846  * var el = Roo.get("foo");
12847  * var mgr = el.getUpdateManager();
12848  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
12849  * ...
12850  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
12851  * <br>
12852  * // or directly (returns the same UpdateManager instance)
12853  * var mgr = new Roo.UpdateManager("myElementId");
12854  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
12855  * mgr.on("update", myFcnNeedsToKnow);
12856  * <br>
12857    // short handed call directly from the element object
12858    Roo.get("foo").load({
12859         url: "bar.php",
12860         scripts:true,
12861         params: "for=bar",
12862         text: "Loading Foo..."
12863    });
12864  * </code></pre>
12865  * @constructor
12866  * Create new UpdateManager directly.
12867  * @param {String/HTMLElement/Roo.Element} el The element to update
12868  * @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).
12869  */
12870 Roo.UpdateManager = function(el, forceNew){
12871     el = Roo.get(el);
12872     if(!forceNew && el.updateManager){
12873         return el.updateManager;
12874     }
12875     /**
12876      * The Element object
12877      * @type Roo.Element
12878      */
12879     this.el = el;
12880     /**
12881      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
12882      * @type String
12883      */
12884     this.defaultUrl = null;
12885
12886     this.addEvents({
12887         /**
12888          * @event beforeupdate
12889          * Fired before an update is made, return false from your handler and the update is cancelled.
12890          * @param {Roo.Element} el
12891          * @param {String/Object/Function} url
12892          * @param {String/Object} params
12893          */
12894         "beforeupdate": true,
12895         /**
12896          * @event update
12897          * Fired after successful update is made.
12898          * @param {Roo.Element} el
12899          * @param {Object} oResponseObject The response Object
12900          */
12901         "update": true,
12902         /**
12903          * @event failure
12904          * Fired on update failure.
12905          * @param {Roo.Element} el
12906          * @param {Object} oResponseObject The response Object
12907          */
12908         "failure": true
12909     });
12910     var d = Roo.UpdateManager.defaults;
12911     /**
12912      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
12913      * @type String
12914      */
12915     this.sslBlankUrl = d.sslBlankUrl;
12916     /**
12917      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
12918      * @type Boolean
12919      */
12920     this.disableCaching = d.disableCaching;
12921     /**
12922      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
12923      * @type String
12924      */
12925     this.indicatorText = d.indicatorText;
12926     /**
12927      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
12928      * @type String
12929      */
12930     this.showLoadIndicator = d.showLoadIndicator;
12931     /**
12932      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
12933      * @type Number
12934      */
12935     this.timeout = d.timeout;
12936
12937     /**
12938      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
12939      * @type Boolean
12940      */
12941     this.loadScripts = d.loadScripts;
12942
12943     /**
12944      * Transaction object of current executing transaction
12945      */
12946     this.transaction = null;
12947
12948     /**
12949      * @private
12950      */
12951     this.autoRefreshProcId = null;
12952     /**
12953      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
12954      * @type Function
12955      */
12956     this.refreshDelegate = this.refresh.createDelegate(this);
12957     /**
12958      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
12959      * @type Function
12960      */
12961     this.updateDelegate = this.update.createDelegate(this);
12962     /**
12963      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
12964      * @type Function
12965      */
12966     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
12967     /**
12968      * @private
12969      */
12970     this.successDelegate = this.processSuccess.createDelegate(this);
12971     /**
12972      * @private
12973      */
12974     this.failureDelegate = this.processFailure.createDelegate(this);
12975
12976     if(!this.renderer){
12977      /**
12978       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
12979       */
12980     this.renderer = new Roo.UpdateManager.BasicRenderer();
12981     }
12982     
12983     Roo.UpdateManager.superclass.constructor.call(this);
12984 };
12985
12986 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
12987     /**
12988      * Get the Element this UpdateManager is bound to
12989      * @return {Roo.Element} The element
12990      */
12991     getEl : function(){
12992         return this.el;
12993     },
12994     /**
12995      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
12996      * @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:
12997 <pre><code>
12998 um.update({<br/>
12999     url: "your-url.php",<br/>
13000     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
13001     callback: yourFunction,<br/>
13002     scope: yourObject, //(optional scope)  <br/>
13003     discardUrl: false, <br/>
13004     nocache: false,<br/>
13005     text: "Loading...",<br/>
13006     timeout: 30,<br/>
13007     scripts: false<br/>
13008 });
13009 </code></pre>
13010      * The only required property is url. The optional properties nocache, text and scripts
13011      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
13012      * @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}
13013      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
13014      * @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.
13015      */
13016     update : function(url, params, callback, discardUrl){
13017         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
13018             var method = this.method,
13019                 cfg;
13020             if(typeof url == "object"){ // must be config object
13021                 cfg = url;
13022                 url = cfg.url;
13023                 params = params || cfg.params;
13024                 callback = callback || cfg.callback;
13025                 discardUrl = discardUrl || cfg.discardUrl;
13026                 if(callback && cfg.scope){
13027                     callback = callback.createDelegate(cfg.scope);
13028                 }
13029                 if(typeof cfg.method != "undefined"){method = cfg.method;};
13030                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
13031                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
13032                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
13033                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
13034             }
13035             this.showLoading();
13036             if(!discardUrl){
13037                 this.defaultUrl = url;
13038             }
13039             if(typeof url == "function"){
13040                 url = url.call(this);
13041             }
13042
13043             method = method || (params ? "POST" : "GET");
13044             if(method == "GET"){
13045                 url = this.prepareUrl(url);
13046             }
13047
13048             var o = Roo.apply(cfg ||{}, {
13049                 url : url,
13050                 params: params,
13051                 success: this.successDelegate,
13052                 failure: this.failureDelegate,
13053                 callback: undefined,
13054                 timeout: (this.timeout*1000),
13055                 argument: {"url": url, "form": null, "callback": callback, "params": params}
13056             });
13057             Roo.log("updated manager called with timeout of " + o.timeout);
13058             this.transaction = Roo.Ajax.request(o);
13059         }
13060     },
13061
13062     /**
13063      * 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.
13064      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
13065      * @param {String/HTMLElement} form The form Id or form element
13066      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
13067      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
13068      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
13069      */
13070     formUpdate : function(form, url, reset, callback){
13071         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
13072             if(typeof url == "function"){
13073                 url = url.call(this);
13074             }
13075             form = Roo.getDom(form);
13076             this.transaction = Roo.Ajax.request({
13077                 form: form,
13078                 url:url,
13079                 success: this.successDelegate,
13080                 failure: this.failureDelegate,
13081                 timeout: (this.timeout*1000),
13082                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
13083             });
13084             this.showLoading.defer(1, this);
13085         }
13086     },
13087
13088     /**
13089      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
13090      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
13091      */
13092     refresh : function(callback){
13093         if(this.defaultUrl == null){
13094             return;
13095         }
13096         this.update(this.defaultUrl, null, callback, true);
13097     },
13098
13099     /**
13100      * Set this element to auto refresh.
13101      * @param {Number} interval How often to update (in seconds).
13102      * @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)
13103      * @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}
13104      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
13105      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
13106      */
13107     startAutoRefresh : function(interval, url, params, callback, refreshNow){
13108         if(refreshNow){
13109             this.update(url || this.defaultUrl, params, callback, true);
13110         }
13111         if(this.autoRefreshProcId){
13112             clearInterval(this.autoRefreshProcId);
13113         }
13114         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
13115     },
13116
13117     /**
13118      * Stop auto refresh on this element.
13119      */
13120      stopAutoRefresh : function(){
13121         if(this.autoRefreshProcId){
13122             clearInterval(this.autoRefreshProcId);
13123             delete this.autoRefreshProcId;
13124         }
13125     },
13126
13127     isAutoRefreshing : function(){
13128        return this.autoRefreshProcId ? true : false;
13129     },
13130     /**
13131      * Called to update the element to "Loading" state. Override to perform custom action.
13132      */
13133     showLoading : function(){
13134         if(this.showLoadIndicator){
13135             this.el.update(this.indicatorText);
13136         }
13137     },
13138
13139     /**
13140      * Adds unique parameter to query string if disableCaching = true
13141      * @private
13142      */
13143     prepareUrl : function(url){
13144         if(this.disableCaching){
13145             var append = "_dc=" + (new Date().getTime());
13146             if(url.indexOf("?") !== -1){
13147                 url += "&" + append;
13148             }else{
13149                 url += "?" + append;
13150             }
13151         }
13152         return url;
13153     },
13154
13155     /**
13156      * @private
13157      */
13158     processSuccess : function(response){
13159         this.transaction = null;
13160         if(response.argument.form && response.argument.reset){
13161             try{ // put in try/catch since some older FF releases had problems with this
13162                 response.argument.form.reset();
13163             }catch(e){}
13164         }
13165         if(this.loadScripts){
13166             this.renderer.render(this.el, response, this,
13167                 this.updateComplete.createDelegate(this, [response]));
13168         }else{
13169             this.renderer.render(this.el, response, this);
13170             this.updateComplete(response);
13171         }
13172     },
13173
13174     updateComplete : function(response){
13175         this.fireEvent("update", this.el, response);
13176         if(typeof response.argument.callback == "function"){
13177             response.argument.callback(this.el, true, response);
13178         }
13179     },
13180
13181     /**
13182      * @private
13183      */
13184     processFailure : function(response){
13185         this.transaction = null;
13186         this.fireEvent("failure", this.el, response);
13187         if(typeof response.argument.callback == "function"){
13188             response.argument.callback(this.el, false, response);
13189         }
13190     },
13191
13192     /**
13193      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
13194      * @param {Object} renderer The object implementing the render() method
13195      */
13196     setRenderer : function(renderer){
13197         this.renderer = renderer;
13198     },
13199
13200     getRenderer : function(){
13201        return this.renderer;
13202     },
13203
13204     /**
13205      * Set the defaultUrl used for updates
13206      * @param {String/Function} defaultUrl The url or a function to call to get the url
13207      */
13208     setDefaultUrl : function(defaultUrl){
13209         this.defaultUrl = defaultUrl;
13210     },
13211
13212     /**
13213      * Aborts the executing transaction
13214      */
13215     abort : function(){
13216         if(this.transaction){
13217             Roo.Ajax.abort(this.transaction);
13218         }
13219     },
13220
13221     /**
13222      * Returns true if an update is in progress
13223      * @return {Boolean}
13224      */
13225     isUpdating : function(){
13226         if(this.transaction){
13227             return Roo.Ajax.isLoading(this.transaction);
13228         }
13229         return false;
13230     }
13231 });
13232
13233 /**
13234  * @class Roo.UpdateManager.defaults
13235  * @static (not really - but it helps the doc tool)
13236  * The defaults collection enables customizing the default properties of UpdateManager
13237  */
13238    Roo.UpdateManager.defaults = {
13239        /**
13240          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
13241          * @type Number
13242          */
13243          timeout : 30,
13244
13245          /**
13246          * True to process scripts by default (Defaults to false).
13247          * @type Boolean
13248          */
13249         loadScripts : false,
13250
13251         /**
13252         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
13253         * @type String
13254         */
13255         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
13256         /**
13257          * Whether to append unique parameter on get request to disable caching (Defaults to false).
13258          * @type Boolean
13259          */
13260         disableCaching : false,
13261         /**
13262          * Whether to show indicatorText when loading (Defaults to true).
13263          * @type Boolean
13264          */
13265         showLoadIndicator : true,
13266         /**
13267          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
13268          * @type String
13269          */
13270         indicatorText : '<div class="loading-indicator">Loading...</div>'
13271    };
13272
13273 /**
13274  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
13275  *Usage:
13276  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
13277  * @param {String/HTMLElement/Roo.Element} el The element to update
13278  * @param {String} url The url
13279  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
13280  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
13281  * @static
13282  * @deprecated
13283  * @member Roo.UpdateManager
13284  */
13285 Roo.UpdateManager.updateElement = function(el, url, params, options){
13286     var um = Roo.get(el, true).getUpdateManager();
13287     Roo.apply(um, options);
13288     um.update(url, params, options ? options.callback : null);
13289 };
13290 // alias for backwards compat
13291 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
13292 /**
13293  * @class Roo.UpdateManager.BasicRenderer
13294  * Default Content renderer. Updates the elements innerHTML with the responseText.
13295  */
13296 Roo.UpdateManager.BasicRenderer = function(){};
13297
13298 Roo.UpdateManager.BasicRenderer.prototype = {
13299     /**
13300      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
13301      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
13302      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
13303      * @param {Roo.Element} el The element being rendered
13304      * @param {Object} response The YUI Connect response object
13305      * @param {UpdateManager} updateManager The calling update manager
13306      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
13307      */
13308      render : function(el, response, updateManager, callback){
13309         el.update(response.responseText, updateManager.loadScripts, callback);
13310     }
13311 };
13312 /*
13313  * Based on:
13314  * Roo JS
13315  * (c)) Alan Knowles
13316  * Licence : LGPL
13317  */
13318
13319
13320 /**
13321  * @class Roo.DomTemplate
13322  * @extends Roo.Template
13323  * An effort at a dom based template engine..
13324  *
13325  * Similar to XTemplate, except it uses dom parsing to create the template..
13326  *
13327  * Supported features:
13328  *
13329  *  Tags:
13330
13331 <pre><code>
13332       {a_variable} - output encoded.
13333       {a_variable.format:("Y-m-d")} - call a method on the variable
13334       {a_variable:raw} - unencoded output
13335       {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
13336       {a_variable:this.method_on_template(...)} - call a method on the template object.
13337  
13338 </code></pre>
13339  *  The tpl tag:
13340 <pre><code>
13341         &lt;div roo-for="a_variable or condition.."&gt;&lt;/div&gt;
13342         &lt;div roo-if="a_variable or condition"&gt;&lt;/div&gt;
13343         &lt;div roo-exec="some javascript"&gt;&lt;/div&gt;
13344         &lt;div roo-name="named_template"&gt;&lt;/div&gt; 
13345   
13346 </code></pre>
13347  *      
13348  */
13349 Roo.DomTemplate = function()
13350 {
13351      Roo.DomTemplate.superclass.constructor.apply(this, arguments);
13352      if (this.html) {
13353         this.compile();
13354      }
13355 };
13356
13357
13358 Roo.extend(Roo.DomTemplate, Roo.Template, {
13359     /**
13360      * id counter for sub templates.
13361      */
13362     id : 0,
13363     /**
13364      * flag to indicate if dom parser is inside a pre,
13365      * it will strip whitespace if not.
13366      */
13367     inPre : false,
13368     
13369     /**
13370      * The various sub templates
13371      */
13372     tpls : false,
13373     
13374     
13375     
13376     /**
13377      *
13378      * basic tag replacing syntax
13379      * WORD:WORD()
13380      *
13381      * // you can fake an object call by doing this
13382      *  x.t:(test,tesT) 
13383      * 
13384      */
13385     re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
13386     //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
13387     
13388     iterChild : function (node, method) {
13389         
13390         var oldPre = this.inPre;
13391         if (node.tagName == 'PRE') {
13392             this.inPre = true;
13393         }
13394         for( var i = 0; i < node.childNodes.length; i++) {
13395             method.call(this, node.childNodes[i]);
13396         }
13397         this.inPre = oldPre;
13398     },
13399     
13400     
13401     
13402     /**
13403      * compile the template
13404      *
13405      * This is not recursive, so I'm not sure how nested templates are really going to be handled..
13406      *
13407      */
13408     compile: function()
13409     {
13410         var s = this.html;
13411         
13412         // covert the html into DOM...
13413         var doc = false;
13414         var div =false;
13415         try {
13416             doc = document.implementation.createHTMLDocument("");
13417             doc.documentElement.innerHTML =   this.html  ;
13418             div = doc.documentElement;
13419         } catch (e) {
13420             // old IE... - nasty -- it causes all sorts of issues.. with
13421             // images getting pulled from server..
13422             div = document.createElement('div');
13423             div.innerHTML = this.html;
13424         }
13425         //doc.documentElement.innerHTML = htmlBody
13426          
13427         
13428         
13429         this.tpls = [];
13430         var _t = this;
13431         this.iterChild(div, function(n) {_t.compileNode(n, true); });
13432         
13433         var tpls = this.tpls;
13434         
13435         // create a top level template from the snippet..
13436         
13437         //Roo.log(div.innerHTML);
13438         
13439         var tpl = {
13440             uid : 'master',
13441             id : this.id++,
13442             attr : false,
13443             value : false,
13444             body : div.innerHTML,
13445             
13446             forCall : false,
13447             execCall : false,
13448             dom : div,
13449             isTop : true
13450             
13451         };
13452         tpls.unshift(tpl);
13453         
13454         
13455         // compile them...
13456         this.tpls = [];
13457         Roo.each(tpls, function(tp){
13458             this.compileTpl(tp);
13459             this.tpls[tp.id] = tp;
13460         }, this);
13461         
13462         this.master = tpls[0];
13463         return this;
13464         
13465         
13466     },
13467     
13468     compileNode : function(node, istop) {
13469         // test for
13470         //Roo.log(node);
13471         
13472         
13473         // skip anything not a tag..
13474         if (node.nodeType != 1) {
13475             if (node.nodeType == 3 && !this.inPre) {
13476                 // reduce white space..
13477                 node.nodeValue = node.nodeValue.replace(/\s+/g, ' '); 
13478                 
13479             }
13480             return;
13481         }
13482         
13483         var tpl = {
13484             uid : false,
13485             id : false,
13486             attr : false,
13487             value : false,
13488             body : '',
13489             
13490             forCall : false,
13491             execCall : false,
13492             dom : false,
13493             isTop : istop
13494             
13495             
13496         };
13497         
13498         
13499         switch(true) {
13500             case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
13501             case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
13502             case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
13503             case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
13504             // no default..
13505         }
13506         
13507         
13508         if (!tpl.attr) {
13509             // just itterate children..
13510             this.iterChild(node,this.compileNode);
13511             return;
13512         }
13513         tpl.uid = this.id++;
13514         tpl.value = node.getAttribute('roo-' +  tpl.attr);
13515         node.removeAttribute('roo-'+ tpl.attr);
13516         if (tpl.attr != 'name') {
13517             var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
13518             node.parentNode.replaceChild(placeholder,  node);
13519         } else {
13520             
13521             var placeholder =  document.createElement('span');
13522             placeholder.className = 'roo-tpl-' + tpl.value;
13523             node.parentNode.replaceChild(placeholder,  node);
13524         }
13525         
13526         // parent now sees '{domtplXXXX}
13527         this.iterChild(node,this.compileNode);
13528         
13529         // we should now have node body...
13530         var div = document.createElement('div');
13531         div.appendChild(node);
13532         tpl.dom = node;
13533         // this has the unfortunate side effect of converting tagged attributes
13534         // eg. href="{...}" into %7C...%7D
13535         // this has been fixed by searching for those combo's although it's a bit hacky..
13536         
13537         
13538         tpl.body = div.innerHTML;
13539         
13540         
13541          
13542         tpl.id = tpl.uid;
13543         switch(tpl.attr) {
13544             case 'for' :
13545                 switch (tpl.value) {
13546                     case '.':  tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
13547                     case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
13548                     default:   tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
13549                 }
13550                 break;
13551             
13552             case 'exec':
13553                 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
13554                 break;
13555             
13556             case 'if':     
13557                 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
13558                 break;
13559             
13560             case 'name':
13561                 tpl.id  = tpl.value; // replace non characters???
13562                 break;
13563             
13564         }
13565         
13566         
13567         this.tpls.push(tpl);
13568         
13569         
13570         
13571     },
13572     
13573     
13574     
13575     
13576     /**
13577      * Compile a segment of the template into a 'sub-template'
13578      *
13579      * 
13580      * 
13581      *
13582      */
13583     compileTpl : function(tpl)
13584     {
13585         var fm = Roo.util.Format;
13586         var useF = this.disableFormats !== true;
13587         
13588         var sep = Roo.isGecko ? "+\n" : ",\n";
13589         
13590         var undef = function(str) {
13591             Roo.debug && Roo.log("Property not found :"  + str);
13592             return '';
13593         };
13594           
13595         //Roo.log(tpl.body);
13596         
13597         
13598         
13599         var fn = function(m, lbrace, name, format, args)
13600         {
13601             //Roo.log("ARGS");
13602             //Roo.log(arguments);
13603             args = args ? args.replace(/\\'/g,"'") : args;
13604             //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
13605             if (typeof(format) == 'undefined') {
13606                 format =  'htmlEncode'; 
13607             }
13608             if (format == 'raw' ) {
13609                 format = false;
13610             }
13611             
13612             if(name.substr(0, 6) == 'domtpl'){
13613                 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
13614             }
13615             
13616             // build an array of options to determine if value is undefined..
13617             
13618             // basically get 'xxxx.yyyy' then do
13619             // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
13620             //    (function () { Roo.log("Property not found"); return ''; })() :
13621             //    ......
13622             
13623             var udef_ar = [];
13624             var lookfor = '';
13625             Roo.each(name.split('.'), function(st) {
13626                 lookfor += (lookfor.length ? '.': '') + st;
13627                 udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
13628             });
13629             
13630             var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
13631             
13632             
13633             if(format && useF){
13634                 
13635                 args = args ? ',' + args : "";
13636                  
13637                 if(format.substr(0, 5) != "this."){
13638                     format = "fm." + format + '(';
13639                 }else{
13640                     format = 'this.call("'+ format.substr(5) + '", ';
13641                     args = ", values";
13642                 }
13643                 
13644                 return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
13645             }
13646              
13647             if (args && args.length) {
13648                 // called with xxyx.yuu:(test,test)
13649                 // change to ()
13650                 return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
13651             }
13652             // raw.. - :raw modifier..
13653             return "'"+ sep + udef_st  + name + ")"+sep+"'";
13654             
13655         };
13656         var body;
13657         // branched to use + in gecko and [].join() in others
13658         if(Roo.isGecko){
13659             body = "tpl.compiled = function(values, parent){  with(values) { return '" +
13660                    tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
13661                     "';};};";
13662         }else{
13663             body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
13664             body.push(tpl.body.replace(/(\r\n|\n)/g,
13665                             '\\n').replace(/'/g, "\\'").replace(this.re, fn));
13666             body.push("'].join('');};};");
13667             body = body.join('');
13668         }
13669         
13670         Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
13671        
13672         /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
13673         eval(body);
13674         
13675         return this;
13676     },
13677      
13678     /**
13679      * same as applyTemplate, except it's done to one of the subTemplates
13680      * when using named templates, you can do:
13681      *
13682      * var str = pl.applySubTemplate('your-name', values);
13683      *
13684      * 
13685      * @param {Number} id of the template
13686      * @param {Object} values to apply to template
13687      * @param {Object} parent (normaly the instance of this object)
13688      */
13689     applySubTemplate : function(id, values, parent)
13690     {
13691         
13692         
13693         var t = this.tpls[id];
13694         
13695         
13696         try { 
13697             if(t.ifCall && !t.ifCall.call(this, values, parent)){
13698                 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
13699                 return '';
13700             }
13701         } catch(e) {
13702             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
13703             Roo.log(values);
13704           
13705             return '';
13706         }
13707         try { 
13708             
13709             if(t.execCall && t.execCall.call(this, values, parent)){
13710                 return '';
13711             }
13712         } catch(e) {
13713             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
13714             Roo.log(values);
13715             return '';
13716         }
13717         
13718         try {
13719             var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
13720             parent = t.target ? values : parent;
13721             if(t.forCall && vs instanceof Array){
13722                 var buf = [];
13723                 for(var i = 0, len = vs.length; i < len; i++){
13724                     try {
13725                         buf[buf.length] = t.compiled.call(this, vs[i], parent);
13726                     } catch (e) {
13727                         Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
13728                         Roo.log(e.body);
13729                         //Roo.log(t.compiled);
13730                         Roo.log(vs[i]);
13731                     }   
13732                 }
13733                 return buf.join('');
13734             }
13735         } catch (e) {
13736             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
13737             Roo.log(values);
13738             return '';
13739         }
13740         try {
13741             return t.compiled.call(this, vs, parent);
13742         } catch (e) {
13743             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
13744             Roo.log(e.body);
13745             //Roo.log(t.compiled);
13746             Roo.log(values);
13747             return '';
13748         }
13749     },
13750
13751    
13752
13753     applyTemplate : function(values){
13754         return this.master.compiled.call(this, values, {});
13755         //var s = this.subs;
13756     },
13757
13758     apply : function(){
13759         return this.applyTemplate.apply(this, arguments);
13760     }
13761
13762  });
13763
13764 Roo.DomTemplate.from = function(el){
13765     el = Roo.getDom(el);
13766     return new Roo.Domtemplate(el.value || el.innerHTML);
13767 };/*
13768  * Based on:
13769  * Ext JS Library 1.1.1
13770  * Copyright(c) 2006-2007, Ext JS, LLC.
13771  *
13772  * Originally Released Under LGPL - original licence link has changed is not relivant.
13773  *
13774  * Fork - LGPL
13775  * <script type="text/javascript">
13776  */
13777
13778 /**
13779  * @class Roo.util.DelayedTask
13780  * Provides a convenient method of performing setTimeout where a new
13781  * timeout cancels the old timeout. An example would be performing validation on a keypress.
13782  * You can use this class to buffer
13783  * the keypress events for a certain number of milliseconds, and perform only if they stop
13784  * for that amount of time.
13785  * @constructor The parameters to this constructor serve as defaults and are not required.
13786  * @param {Function} fn (optional) The default function to timeout
13787  * @param {Object} scope (optional) The default scope of that timeout
13788  * @param {Array} args (optional) The default Array of arguments
13789  */
13790 Roo.util.DelayedTask = function(fn, scope, args){
13791     var id = null, d, t;
13792
13793     var call = function(){
13794         var now = new Date().getTime();
13795         if(now - t >= d){
13796             clearInterval(id);
13797             id = null;
13798             fn.apply(scope, args || []);
13799         }
13800     };
13801     /**
13802      * Cancels any pending timeout and queues a new one
13803      * @param {Number} delay The milliseconds to delay
13804      * @param {Function} newFn (optional) Overrides function passed to constructor
13805      * @param {Object} newScope (optional) Overrides scope passed to constructor
13806      * @param {Array} newArgs (optional) Overrides args passed to constructor
13807      */
13808     this.delay = function(delay, newFn, newScope, newArgs){
13809         if(id && delay != d){
13810             this.cancel();
13811         }
13812         d = delay;
13813         t = new Date().getTime();
13814         fn = newFn || fn;
13815         scope = newScope || scope;
13816         args = newArgs || args;
13817         if(!id){
13818             id = setInterval(call, d);
13819         }
13820     };
13821
13822     /**
13823      * Cancel the last queued timeout
13824      */
13825     this.cancel = function(){
13826         if(id){
13827             clearInterval(id);
13828             id = null;
13829         }
13830     };
13831 };/*
13832  * Based on:
13833  * Ext JS Library 1.1.1
13834  * Copyright(c) 2006-2007, Ext JS, LLC.
13835  *
13836  * Originally Released Under LGPL - original licence link has changed is not relivant.
13837  *
13838  * Fork - LGPL
13839  * <script type="text/javascript">
13840  */
13841 /**
13842  * @class Roo.util.TaskRunner
13843  * Manage background tasks - not sure why this is better that setInterval?
13844  * @static
13845  *
13846  */
13847  
13848 Roo.util.TaskRunner = function(interval){
13849     interval = interval || 10;
13850     var tasks = [], removeQueue = [];
13851     var id = 0;
13852     var running = false;
13853
13854     var stopThread = function(){
13855         running = false;
13856         clearInterval(id);
13857         id = 0;
13858     };
13859
13860     var startThread = function(){
13861         if(!running){
13862             running = true;
13863             id = setInterval(runTasks, interval);
13864         }
13865     };
13866
13867     var removeTask = function(task){
13868         removeQueue.push(task);
13869         if(task.onStop){
13870             task.onStop();
13871         }
13872     };
13873
13874     var runTasks = function(){
13875         if(removeQueue.length > 0){
13876             for(var i = 0, len = removeQueue.length; i < len; i++){
13877                 tasks.remove(removeQueue[i]);
13878             }
13879             removeQueue = [];
13880             if(tasks.length < 1){
13881                 stopThread();
13882                 return;
13883             }
13884         }
13885         var now = new Date().getTime();
13886         for(var i = 0, len = tasks.length; i < len; ++i){
13887             var t = tasks[i];
13888             var itime = now - t.taskRunTime;
13889             if(t.interval <= itime){
13890                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
13891                 t.taskRunTime = now;
13892                 if(rt === false || t.taskRunCount === t.repeat){
13893                     removeTask(t);
13894                     return;
13895                 }
13896             }
13897             if(t.duration && t.duration <= (now - t.taskStartTime)){
13898                 removeTask(t);
13899             }
13900         }
13901     };
13902
13903     /**
13904      * Queues a new task.
13905      * @param {Object} task
13906      *
13907      * Task property : interval = how frequent to run.
13908      * Task object should implement
13909      * function run()
13910      * Task object may implement
13911      * function onStop()
13912      */
13913     this.start = function(task){
13914         tasks.push(task);
13915         task.taskStartTime = new Date().getTime();
13916         task.taskRunTime = 0;
13917         task.taskRunCount = 0;
13918         startThread();
13919         return task;
13920     };
13921     /**
13922      * Stop  new task.
13923      * @param {Object} task
13924      */
13925     this.stop = function(task){
13926         removeTask(task);
13927         return task;
13928     };
13929     /**
13930      * Stop all Tasks
13931      */
13932     this.stopAll = function(){
13933         stopThread();
13934         for(var i = 0, len = tasks.length; i < len; i++){
13935             if(tasks[i].onStop){
13936                 tasks[i].onStop();
13937             }
13938         }
13939         tasks = [];
13940         removeQueue = [];
13941     };
13942 };
13943
13944 Roo.TaskMgr = new Roo.util.TaskRunner();/*
13945  * Based on:
13946  * Ext JS Library 1.1.1
13947  * Copyright(c) 2006-2007, Ext JS, LLC.
13948  *
13949  * Originally Released Under LGPL - original licence link has changed is not relivant.
13950  *
13951  * Fork - LGPL
13952  * <script type="text/javascript">
13953  */
13954
13955  
13956 /**
13957  * @class Roo.util.MixedCollection
13958  * @extends Roo.util.Observable
13959  * A Collection class that maintains both numeric indexes and keys and exposes events.
13960  * @constructor
13961  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
13962  * collection (defaults to false)
13963  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
13964  * and return the key value for that item.  This is used when available to look up the key on items that
13965  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
13966  * equivalent to providing an implementation for the {@link #getKey} method.
13967  */
13968 Roo.util.MixedCollection = function(allowFunctions, keyFn){
13969     this.items = [];
13970     this.map = {};
13971     this.keys = [];
13972     this.length = 0;
13973     this.addEvents({
13974         /**
13975          * @event clear
13976          * Fires when the collection is cleared.
13977          */
13978         "clear" : true,
13979         /**
13980          * @event add
13981          * Fires when an item is added to the collection.
13982          * @param {Number} index The index at which the item was added.
13983          * @param {Object} o The item added.
13984          * @param {String} key The key associated with the added item.
13985          */
13986         "add" : true,
13987         /**
13988          * @event replace
13989          * Fires when an item is replaced in the collection.
13990          * @param {String} key he key associated with the new added.
13991          * @param {Object} old The item being replaced.
13992          * @param {Object} new The new item.
13993          */
13994         "replace" : true,
13995         /**
13996          * @event remove
13997          * Fires when an item is removed from the collection.
13998          * @param {Object} o The item being removed.
13999          * @param {String} key (optional) The key associated with the removed item.
14000          */
14001         "remove" : true,
14002         "sort" : true
14003     });
14004     this.allowFunctions = allowFunctions === true;
14005     if(keyFn){
14006         this.getKey = keyFn;
14007     }
14008     Roo.util.MixedCollection.superclass.constructor.call(this);
14009 };
14010
14011 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
14012     allowFunctions : false,
14013     
14014 /**
14015  * Adds an item to the collection.
14016  * @param {String} key The key to associate with the item
14017  * @param {Object} o The item to add.
14018  * @return {Object} The item added.
14019  */
14020     add : function(key, o){
14021         if(arguments.length == 1){
14022             o = arguments[0];
14023             key = this.getKey(o);
14024         }
14025         if(typeof key == "undefined" || key === null){
14026             this.length++;
14027             this.items.push(o);
14028             this.keys.push(null);
14029         }else{
14030             var old = this.map[key];
14031             if(old){
14032                 return this.replace(key, o);
14033             }
14034             this.length++;
14035             this.items.push(o);
14036             this.map[key] = o;
14037             this.keys.push(key);
14038         }
14039         this.fireEvent("add", this.length-1, o, key);
14040         return o;
14041     },
14042        
14043 /**
14044   * MixedCollection has a generic way to fetch keys if you implement getKey.
14045 <pre><code>
14046 // normal way
14047 var mc = new Roo.util.MixedCollection();
14048 mc.add(someEl.dom.id, someEl);
14049 mc.add(otherEl.dom.id, otherEl);
14050 //and so on
14051
14052 // using getKey
14053 var mc = new Roo.util.MixedCollection();
14054 mc.getKey = function(el){
14055    return el.dom.id;
14056 };
14057 mc.add(someEl);
14058 mc.add(otherEl);
14059
14060 // or via the constructor
14061 var mc = new Roo.util.MixedCollection(false, function(el){
14062    return el.dom.id;
14063 });
14064 mc.add(someEl);
14065 mc.add(otherEl);
14066 </code></pre>
14067  * @param o {Object} The item for which to find the key.
14068  * @return {Object} The key for the passed item.
14069  */
14070     getKey : function(o){
14071          return o.id; 
14072     },
14073    
14074 /**
14075  * Replaces an item in the collection.
14076  * @param {String} key The key associated with the item to replace, or the item to replace.
14077  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
14078  * @return {Object}  The new item.
14079  */
14080     replace : function(key, o){
14081         if(arguments.length == 1){
14082             o = arguments[0];
14083             key = this.getKey(o);
14084         }
14085         var old = this.item(key);
14086         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
14087              return this.add(key, o);
14088         }
14089         var index = this.indexOfKey(key);
14090         this.items[index] = o;
14091         this.map[key] = o;
14092         this.fireEvent("replace", key, old, o);
14093         return o;
14094     },
14095    
14096 /**
14097  * Adds all elements of an Array or an Object to the collection.
14098  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
14099  * an Array of values, each of which are added to the collection.
14100  */
14101     addAll : function(objs){
14102         if(arguments.length > 1 || objs instanceof Array){
14103             var args = arguments.length > 1 ? arguments : objs;
14104             for(var i = 0, len = args.length; i < len; i++){
14105                 this.add(args[i]);
14106             }
14107         }else{
14108             for(var key in objs){
14109                 if(this.allowFunctions || typeof objs[key] != "function"){
14110                     this.add(key, objs[key]);
14111                 }
14112             }
14113         }
14114     },
14115    
14116 /**
14117  * Executes the specified function once for every item in the collection, passing each
14118  * item as the first and only parameter. returning false from the function will stop the iteration.
14119  * @param {Function} fn The function to execute for each item.
14120  * @param {Object} scope (optional) The scope in which to execute the function.
14121  */
14122     each : function(fn, scope){
14123         var items = [].concat(this.items); // each safe for removal
14124         for(var i = 0, len = items.length; i < len; i++){
14125             if(fn.call(scope || items[i], items[i], i, len) === false){
14126                 break;
14127             }
14128         }
14129     },
14130    
14131 /**
14132  * Executes the specified function once for every key in the collection, passing each
14133  * key, and its associated item as the first two parameters.
14134  * @param {Function} fn The function to execute for each item.
14135  * @param {Object} scope (optional) The scope in which to execute the function.
14136  */
14137     eachKey : function(fn, scope){
14138         for(var i = 0, len = this.keys.length; i < len; i++){
14139             fn.call(scope || window, this.keys[i], this.items[i], i, len);
14140         }
14141     },
14142    
14143 /**
14144  * Returns the first item in the collection which elicits a true return value from the
14145  * passed selection function.
14146  * @param {Function} fn The selection function to execute for each item.
14147  * @param {Object} scope (optional) The scope in which to execute the function.
14148  * @return {Object} The first item in the collection which returned true from the selection function.
14149  */
14150     find : function(fn, scope){
14151         for(var i = 0, len = this.items.length; i < len; i++){
14152             if(fn.call(scope || window, this.items[i], this.keys[i])){
14153                 return this.items[i];
14154             }
14155         }
14156         return null;
14157     },
14158    
14159 /**
14160  * Inserts an item at the specified index in the collection.
14161  * @param {Number} index The index to insert the item at.
14162  * @param {String} key The key to associate with the new item, or the item itself.
14163  * @param {Object} o  (optional) If the second parameter was a key, the new item.
14164  * @return {Object} The item inserted.
14165  */
14166     insert : function(index, key, o){
14167         if(arguments.length == 2){
14168             o = arguments[1];
14169             key = this.getKey(o);
14170         }
14171         if(index >= this.length){
14172             return this.add(key, o);
14173         }
14174         this.length++;
14175         this.items.splice(index, 0, o);
14176         if(typeof key != "undefined" && key != null){
14177             this.map[key] = o;
14178         }
14179         this.keys.splice(index, 0, key);
14180         this.fireEvent("add", index, o, key);
14181         return o;
14182     },
14183    
14184 /**
14185  * Removed an item from the collection.
14186  * @param {Object} o The item to remove.
14187  * @return {Object} The item removed.
14188  */
14189     remove : function(o){
14190         return this.removeAt(this.indexOf(o));
14191     },
14192    
14193 /**
14194  * Remove an item from a specified index in the collection.
14195  * @param {Number} index The index within the collection of the item to remove.
14196  */
14197     removeAt : function(index){
14198         if(index < this.length && index >= 0){
14199             this.length--;
14200             var o = this.items[index];
14201             this.items.splice(index, 1);
14202             var key = this.keys[index];
14203             if(typeof key != "undefined"){
14204                 delete this.map[key];
14205             }
14206             this.keys.splice(index, 1);
14207             this.fireEvent("remove", o, key);
14208         }
14209     },
14210    
14211 /**
14212  * Removed an item associated with the passed key fom the collection.
14213  * @param {String} key The key of the item to remove.
14214  */
14215     removeKey : function(key){
14216         return this.removeAt(this.indexOfKey(key));
14217     },
14218    
14219 /**
14220  * Returns the number of items in the collection.
14221  * @return {Number} the number of items in the collection.
14222  */
14223     getCount : function(){
14224         return this.length; 
14225     },
14226    
14227 /**
14228  * Returns index within the collection of the passed Object.
14229  * @param {Object} o The item to find the index of.
14230  * @return {Number} index of the item.
14231  */
14232     indexOf : function(o){
14233         if(!this.items.indexOf){
14234             for(var i = 0, len = this.items.length; i < len; i++){
14235                 if(this.items[i] == o) {
14236                     return i;
14237                 }
14238             }
14239             return -1;
14240         }else{
14241             return this.items.indexOf(o);
14242         }
14243     },
14244    
14245 /**
14246  * Returns index within the collection of the passed key.
14247  * @param {String} key The key to find the index of.
14248  * @return {Number} index of the key.
14249  */
14250     indexOfKey : function(key){
14251         if(!this.keys.indexOf){
14252             for(var i = 0, len = this.keys.length; i < len; i++){
14253                 if(this.keys[i] == key) {
14254                     return i;
14255                 }
14256             }
14257             return -1;
14258         }else{
14259             return this.keys.indexOf(key);
14260         }
14261     },
14262    
14263 /**
14264  * Returns the item associated with the passed key OR index. Key has priority over index.
14265  * @param {String/Number} key The key or index of the item.
14266  * @return {Object} The item associated with the passed key.
14267  */
14268     item : function(key){
14269         if (key === 'length') {
14270             return null;
14271         }
14272         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
14273         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
14274     },
14275     
14276 /**
14277  * Returns the item at the specified index.
14278  * @param {Number} index The index of the item.
14279  * @return {Object}
14280  */
14281     itemAt : function(index){
14282         return this.items[index];
14283     },
14284     
14285 /**
14286  * Returns the item associated with the passed key.
14287  * @param {String/Number} key The key of the item.
14288  * @return {Object} The item associated with the passed key.
14289  */
14290     key : function(key){
14291         return this.map[key];
14292     },
14293    
14294 /**
14295  * Returns true if the collection contains the passed Object as an item.
14296  * @param {Object} o  The Object to look for in the collection.
14297  * @return {Boolean} True if the collection contains the Object as an item.
14298  */
14299     contains : function(o){
14300         return this.indexOf(o) != -1;
14301     },
14302    
14303 /**
14304  * Returns true if the collection contains the passed Object as a key.
14305  * @param {String} key The key to look for in the collection.
14306  * @return {Boolean} True if the collection contains the Object as a key.
14307  */
14308     containsKey : function(key){
14309         return typeof this.map[key] != "undefined";
14310     },
14311    
14312 /**
14313  * Removes all items from the collection.
14314  */
14315     clear : function(){
14316         this.length = 0;
14317         this.items = [];
14318         this.keys = [];
14319         this.map = {};
14320         this.fireEvent("clear");
14321     },
14322    
14323 /**
14324  * Returns the first item in the collection.
14325  * @return {Object} the first item in the collection..
14326  */
14327     first : function(){
14328         return this.items[0]; 
14329     },
14330    
14331 /**
14332  * Returns the last item in the collection.
14333  * @return {Object} the last item in the collection..
14334  */
14335     last : function(){
14336         return this.items[this.length-1];   
14337     },
14338     
14339     _sort : function(property, dir, fn){
14340         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
14341         fn = fn || function(a, b){
14342             return a-b;
14343         };
14344         var c = [], k = this.keys, items = this.items;
14345         for(var i = 0, len = items.length; i < len; i++){
14346             c[c.length] = {key: k[i], value: items[i], index: i};
14347         }
14348         c.sort(function(a, b){
14349             var v = fn(a[property], b[property]) * dsc;
14350             if(v == 0){
14351                 v = (a.index < b.index ? -1 : 1);
14352             }
14353             return v;
14354         });
14355         for(var i = 0, len = c.length; i < len; i++){
14356             items[i] = c[i].value;
14357             k[i] = c[i].key;
14358         }
14359         this.fireEvent("sort", this);
14360     },
14361     
14362     /**
14363      * Sorts this collection with the passed comparison function
14364      * @param {String} direction (optional) "ASC" or "DESC"
14365      * @param {Function} fn (optional) comparison function
14366      */
14367     sort : function(dir, fn){
14368         this._sort("value", dir, fn);
14369     },
14370     
14371     /**
14372      * Sorts this collection by keys
14373      * @param {String} direction (optional) "ASC" or "DESC"
14374      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
14375      */
14376     keySort : function(dir, fn){
14377         this._sort("key", dir, fn || function(a, b){
14378             return String(a).toUpperCase()-String(b).toUpperCase();
14379         });
14380     },
14381     
14382     /**
14383      * Returns a range of items in this collection
14384      * @param {Number} startIndex (optional) defaults to 0
14385      * @param {Number} endIndex (optional) default to the last item
14386      * @return {Array} An array of items
14387      */
14388     getRange : function(start, end){
14389         var items = this.items;
14390         if(items.length < 1){
14391             return [];
14392         }
14393         start = start || 0;
14394         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
14395         var r = [];
14396         if(start <= end){
14397             for(var i = start; i <= end; i++) {
14398                     r[r.length] = items[i];
14399             }
14400         }else{
14401             for(var i = start; i >= end; i--) {
14402                     r[r.length] = items[i];
14403             }
14404         }
14405         return r;
14406     },
14407         
14408     /**
14409      * Filter the <i>objects</i> in this collection by a specific property. 
14410      * Returns a new collection that has been filtered.
14411      * @param {String} property A property on your objects
14412      * @param {String/RegExp} value Either string that the property values 
14413      * should start with or a RegExp to test against the property
14414      * @return {MixedCollection} The new filtered collection
14415      */
14416     filter : function(property, value){
14417         if(!value.exec){ // not a regex
14418             value = String(value);
14419             if(value.length == 0){
14420                 return this.clone();
14421             }
14422             value = new RegExp("^" + Roo.escapeRe(value), "i");
14423         }
14424         return this.filterBy(function(o){
14425             return o && value.test(o[property]);
14426         });
14427         },
14428     
14429     /**
14430      * Filter by a function. * Returns a new collection that has been filtered.
14431      * The passed function will be called with each 
14432      * object in the collection. If the function returns true, the value is included 
14433      * otherwise it is filtered.
14434      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
14435      * @param {Object} scope (optional) The scope of the function (defaults to this) 
14436      * @return {MixedCollection} The new filtered collection
14437      */
14438     filterBy : function(fn, scope){
14439         var r = new Roo.util.MixedCollection();
14440         r.getKey = this.getKey;
14441         var k = this.keys, it = this.items;
14442         for(var i = 0, len = it.length; i < len; i++){
14443             if(fn.call(scope||this, it[i], k[i])){
14444                                 r.add(k[i], it[i]);
14445                         }
14446         }
14447         return r;
14448     },
14449     
14450     /**
14451      * Creates a duplicate of this collection
14452      * @return {MixedCollection}
14453      */
14454     clone : function(){
14455         var r = new Roo.util.MixedCollection();
14456         var k = this.keys, it = this.items;
14457         for(var i = 0, len = it.length; i < len; i++){
14458             r.add(k[i], it[i]);
14459         }
14460         r.getKey = this.getKey;
14461         return r;
14462     }
14463 });
14464 /**
14465  * Returns the item associated with the passed key or index.
14466  * @method
14467  * @param {String/Number} key The key or index of the item.
14468  * @return {Object} The item associated with the passed key.
14469  */
14470 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
14471  * Based on:
14472  * Ext JS Library 1.1.1
14473  * Copyright(c) 2006-2007, Ext JS, LLC.
14474  *
14475  * Originally Released Under LGPL - original licence link has changed is not relivant.
14476  *
14477  * Fork - LGPL
14478  * <script type="text/javascript">
14479  */
14480 /**
14481  * @class Roo.util.JSON
14482  * Modified version of Douglas Crockford"s json.js that doesn"t
14483  * mess with the Object prototype 
14484  * http://www.json.org/js.html
14485  * @static
14486  */
14487 Roo.util.JSON = new (function(){
14488     var useHasOwn = {}.hasOwnProperty ? true : false;
14489     
14490     // crashes Safari in some instances
14491     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
14492     
14493     var pad = function(n) {
14494         return n < 10 ? "0" + n : n;
14495     };
14496     
14497     var m = {
14498         "\b": '\\b',
14499         "\t": '\\t',
14500         "\n": '\\n',
14501         "\f": '\\f',
14502         "\r": '\\r',
14503         '"' : '\\"',
14504         "\\": '\\\\'
14505     };
14506
14507     var encodeString = function(s){
14508         if (/["\\\x00-\x1f]/.test(s)) {
14509             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
14510                 var c = m[b];
14511                 if(c){
14512                     return c;
14513                 }
14514                 c = b.charCodeAt();
14515                 return "\\u00" +
14516                     Math.floor(c / 16).toString(16) +
14517                     (c % 16).toString(16);
14518             }) + '"';
14519         }
14520         return '"' + s + '"';
14521     };
14522     
14523     var encodeArray = function(o){
14524         var a = ["["], b, i, l = o.length, v;
14525             for (i = 0; i < l; i += 1) {
14526                 v = o[i];
14527                 switch (typeof v) {
14528                     case "undefined":
14529                     case "function":
14530                     case "unknown":
14531                         break;
14532                     default:
14533                         if (b) {
14534                             a.push(',');
14535                         }
14536                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
14537                         b = true;
14538                 }
14539             }
14540             a.push("]");
14541             return a.join("");
14542     };
14543     
14544     var encodeDate = function(o){
14545         return '"' + o.getFullYear() + "-" +
14546                 pad(o.getMonth() + 1) + "-" +
14547                 pad(o.getDate()) + "T" +
14548                 pad(o.getHours()) + ":" +
14549                 pad(o.getMinutes()) + ":" +
14550                 pad(o.getSeconds()) + '"';
14551     };
14552     
14553     /**
14554      * Encodes an Object, Array or other value
14555      * @param {Mixed} o The variable to encode
14556      * @return {String} The JSON string
14557      */
14558     this.encode = function(o)
14559     {
14560         // should this be extended to fully wrap stringify..
14561         
14562         if(typeof o == "undefined" || o === null){
14563             return "null";
14564         }else if(o instanceof Array){
14565             return encodeArray(o);
14566         }else if(o instanceof Date){
14567             return encodeDate(o);
14568         }else if(typeof o == "string"){
14569             return encodeString(o);
14570         }else if(typeof o == "number"){
14571             return isFinite(o) ? String(o) : "null";
14572         }else if(typeof o == "boolean"){
14573             return String(o);
14574         }else {
14575             var a = ["{"], b, i, v;
14576             for (i in o) {
14577                 if(!useHasOwn || o.hasOwnProperty(i)) {
14578                     v = o[i];
14579                     switch (typeof v) {
14580                     case "undefined":
14581                     case "function":
14582                     case "unknown":
14583                         break;
14584                     default:
14585                         if(b){
14586                             a.push(',');
14587                         }
14588                         a.push(this.encode(i), ":",
14589                                 v === null ? "null" : this.encode(v));
14590                         b = true;
14591                     }
14592                 }
14593             }
14594             a.push("}");
14595             return a.join("");
14596         }
14597     };
14598     
14599     /**
14600      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
14601      * @param {String} json The JSON string
14602      * @return {Object} The resulting object
14603      */
14604     this.decode = function(json){
14605         
14606         return  /** eval:var:json */ eval("(" + json + ')');
14607     };
14608 })();
14609 /** 
14610  * Shorthand for {@link Roo.util.JSON#encode}
14611  * @member Roo encode 
14612  * @method */
14613 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
14614 /** 
14615  * Shorthand for {@link Roo.util.JSON#decode}
14616  * @member Roo decode 
14617  * @method */
14618 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
14619 /*
14620  * Based on:
14621  * Ext JS Library 1.1.1
14622  * Copyright(c) 2006-2007, Ext JS, LLC.
14623  *
14624  * Originally Released Under LGPL - original licence link has changed is not relivant.
14625  *
14626  * Fork - LGPL
14627  * <script type="text/javascript">
14628  */
14629  
14630 /**
14631  * @class Roo.util.Format
14632  * Reusable data formatting functions
14633  * @static
14634  */
14635 Roo.util.Format = function(){
14636     var trimRe = /^\s+|\s+$/g;
14637     return {
14638         /**
14639          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
14640          * @param {String} value The string to truncate
14641          * @param {Number} length The maximum length to allow before truncating
14642          * @return {String} The converted text
14643          */
14644         ellipsis : function(value, len){
14645             if(value && value.length > len){
14646                 return value.substr(0, len-3)+"...";
14647             }
14648             return value;
14649         },
14650
14651         /**
14652          * Checks a reference and converts it to empty string if it is undefined
14653          * @param {Mixed} value Reference to check
14654          * @return {Mixed} Empty string if converted, otherwise the original value
14655          */
14656         undef : function(value){
14657             return typeof value != "undefined" ? value : "";
14658         },
14659
14660         /**
14661          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
14662          * @param {String} value The string to encode
14663          * @return {String} The encoded text
14664          */
14665         htmlEncode : function(value){
14666             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
14667         },
14668
14669         /**
14670          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
14671          * @param {String} value The string to decode
14672          * @return {String} The decoded text
14673          */
14674         htmlDecode : function(value){
14675             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
14676         },
14677
14678         /**
14679          * Trims any whitespace from either side of a string
14680          * @param {String} value The text to trim
14681          * @return {String} The trimmed text
14682          */
14683         trim : function(value){
14684             return String(value).replace(trimRe, "");
14685         },
14686
14687         /**
14688          * Returns a substring from within an original string
14689          * @param {String} value The original text
14690          * @param {Number} start The start index of the substring
14691          * @param {Number} length The length of the substring
14692          * @return {String} The substring
14693          */
14694         substr : function(value, start, length){
14695             return String(value).substr(start, length);
14696         },
14697
14698         /**
14699          * Converts a string to all lower case letters
14700          * @param {String} value The text to convert
14701          * @return {String} The converted text
14702          */
14703         lowercase : function(value){
14704             return String(value).toLowerCase();
14705         },
14706
14707         /**
14708          * Converts a string to all upper case letters
14709          * @param {String} value The text to convert
14710          * @return {String} The converted text
14711          */
14712         uppercase : function(value){
14713             return String(value).toUpperCase();
14714         },
14715
14716         /**
14717          * Converts the first character only of a string to upper case
14718          * @param {String} value The text to convert
14719          * @return {String} The converted text
14720          */
14721         capitalize : function(value){
14722             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
14723         },
14724
14725         // private
14726         call : function(value, fn){
14727             if(arguments.length > 2){
14728                 var args = Array.prototype.slice.call(arguments, 2);
14729                 args.unshift(value);
14730                  
14731                 return /** eval:var:value */  eval(fn).apply(window, args);
14732             }else{
14733                 /** eval:var:value */
14734                 return /** eval:var:value */ eval(fn).call(window, value);
14735             }
14736         },
14737
14738        
14739         /**
14740          * safer version of Math.toFixed..??/
14741          * @param {Number/String} value The numeric value to format
14742          * @param {Number/String} value Decimal places 
14743          * @return {String} The formatted currency string
14744          */
14745         toFixed : function(v, n)
14746         {
14747             // why not use to fixed - precision is buggered???
14748             if (!n) {
14749                 return Math.round(v-0);
14750             }
14751             var fact = Math.pow(10,n+1);
14752             v = (Math.round((v-0)*fact))/fact;
14753             var z = (''+fact).substring(2);
14754             if (v == Math.floor(v)) {
14755                 return Math.floor(v) + '.' + z;
14756             }
14757             
14758             // now just padd decimals..
14759             var ps = String(v).split('.');
14760             var fd = (ps[1] + z);
14761             var r = fd.substring(0,n); 
14762             var rm = fd.substring(n); 
14763             if (rm < 5) {
14764                 return ps[0] + '.' + r;
14765             }
14766             r*=1; // turn it into a number;
14767             r++;
14768             if (String(r).length != n) {
14769                 ps[0]*=1;
14770                 ps[0]++;
14771                 r = String(r).substring(1); // chop the end off.
14772             }
14773             
14774             return ps[0] + '.' + r;
14775              
14776         },
14777         
14778         /**
14779          * Format a number as US currency
14780          * @param {Number/String} value The numeric value to format
14781          * @return {String} The formatted currency string
14782          */
14783         usMoney : function(v){
14784             return '$' + Roo.util.Format.number(v);
14785         },
14786         
14787         /**
14788          * Format a number
14789          * eventually this should probably emulate php's number_format
14790          * @param {Number/String} value The numeric value to format
14791          * @param {Number} decimals number of decimal places
14792          * @param {String} delimiter for thousands (default comma)
14793          * @return {String} The formatted currency string
14794          */
14795         number : function(v, decimals, thousandsDelimiter)
14796         {
14797             // multiply and round.
14798             decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
14799             thousandsDelimiter = typeof(thousandsDelimiter) == 'undefined' ? ',' : thousandsDelimiter;
14800             
14801             var mul = Math.pow(10, decimals);
14802             var zero = String(mul).substring(1);
14803             v = (Math.round((v-0)*mul))/mul;
14804             
14805             // if it's '0' number.. then
14806             
14807             //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
14808             v = String(v);
14809             var ps = v.split('.');
14810             var whole = ps[0];
14811             
14812             var r = /(\d+)(\d{3})/;
14813             // add comma's
14814             
14815             if(thousandsDelimiter.length != 0) {
14816                 whole = whole.replace(/\B(?=(\d{3})+(?!\d))/g, thousandsDelimiter );
14817             } 
14818             
14819             var sub = ps[1] ?
14820                     // has decimals..
14821                     (decimals ?  ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
14822                     // does not have decimals
14823                     (decimals ? ('.' + zero) : '');
14824             
14825             
14826             return whole + sub ;
14827         },
14828         
14829         /**
14830          * Parse a value into a formatted date using the specified format pattern.
14831          * @param {Mixed} value The value to format
14832          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
14833          * @return {String} The formatted date string
14834          */
14835         date : function(v, format){
14836             if(!v){
14837                 return "";
14838             }
14839             if(!(v instanceof Date)){
14840                 v = new Date(Date.parse(v));
14841             }
14842             return v.dateFormat(format || Roo.util.Format.defaults.date);
14843         },
14844
14845         /**
14846          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
14847          * @param {String} format Any valid date format string
14848          * @return {Function} The date formatting function
14849          */
14850         dateRenderer : function(format){
14851             return function(v){
14852                 return Roo.util.Format.date(v, format);  
14853             };
14854         },
14855
14856         // private
14857         stripTagsRE : /<\/?[^>]+>/gi,
14858         
14859         /**
14860          * Strips all HTML tags
14861          * @param {Mixed} value The text from which to strip tags
14862          * @return {String} The stripped text
14863          */
14864         stripTags : function(v){
14865             return !v ? v : String(v).replace(this.stripTagsRE, "");
14866         },
14867         
14868         /**
14869          * Size in Mb,Gb etc.
14870          * @param {Number} value The number to be formated
14871          * @param {number} decimals how many decimal places
14872          * @return {String} the formated string
14873          */
14874         size : function(value, decimals)
14875         {
14876             var sizes = ['b', 'k', 'M', 'G', 'T'];
14877             if (value == 0) {
14878                 return 0;
14879             }
14880             var i = parseInt(Math.floor(Math.log(value) / Math.log(1024)));
14881             return Roo.util.Format.number(value/ Math.pow(1024, i) ,decimals)   + sizes[i];
14882         }
14883         
14884         
14885         
14886     };
14887 }();
14888 Roo.util.Format.defaults = {
14889     date : 'd/M/Y'
14890 };/*
14891  * Based on:
14892  * Ext JS Library 1.1.1
14893  * Copyright(c) 2006-2007, Ext JS, LLC.
14894  *
14895  * Originally Released Under LGPL - original licence link has changed is not relivant.
14896  *
14897  * Fork - LGPL
14898  * <script type="text/javascript">
14899  */
14900
14901
14902  
14903
14904 /**
14905  * @class Roo.MasterTemplate
14906  * @extends Roo.Template
14907  * Provides a template that can have child templates. The syntax is:
14908 <pre><code>
14909 var t = new Roo.MasterTemplate(
14910         '&lt;select name="{name}"&gt;',
14911                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
14912         '&lt;/select&gt;'
14913 );
14914 t.add('options', {value: 'foo', text: 'bar'});
14915 // or you can add multiple child elements in one shot
14916 t.addAll('options', [
14917     {value: 'foo', text: 'bar'},
14918     {value: 'foo2', text: 'bar2'},
14919     {value: 'foo3', text: 'bar3'}
14920 ]);
14921 // then append, applying the master template values
14922 t.append('my-form', {name: 'my-select'});
14923 </code></pre>
14924 * A name attribute for the child template is not required if you have only one child
14925 * template or you want to refer to them by index.
14926  */
14927 Roo.MasterTemplate = function(){
14928     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
14929     this.originalHtml = this.html;
14930     var st = {};
14931     var m, re = this.subTemplateRe;
14932     re.lastIndex = 0;
14933     var subIndex = 0;
14934     while(m = re.exec(this.html)){
14935         var name = m[1], content = m[2];
14936         st[subIndex] = {
14937             name: name,
14938             index: subIndex,
14939             buffer: [],
14940             tpl : new Roo.Template(content)
14941         };
14942         if(name){
14943             st[name] = st[subIndex];
14944         }
14945         st[subIndex].tpl.compile();
14946         st[subIndex].tpl.call = this.call.createDelegate(this);
14947         subIndex++;
14948     }
14949     this.subCount = subIndex;
14950     this.subs = st;
14951 };
14952 Roo.extend(Roo.MasterTemplate, Roo.Template, {
14953     /**
14954     * The regular expression used to match sub templates
14955     * @type RegExp
14956     * @property
14957     */
14958     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
14959
14960     /**
14961      * Applies the passed values to a child template.
14962      * @param {String/Number} name (optional) The name or index of the child template
14963      * @param {Array/Object} values The values to be applied to the template
14964      * @return {MasterTemplate} this
14965      */
14966      add : function(name, values){
14967         if(arguments.length == 1){
14968             values = arguments[0];
14969             name = 0;
14970         }
14971         var s = this.subs[name];
14972         s.buffer[s.buffer.length] = s.tpl.apply(values);
14973         return this;
14974     },
14975
14976     /**
14977      * Applies all the passed values to a child template.
14978      * @param {String/Number} name (optional) The name or index of the child template
14979      * @param {Array} values The values to be applied to the template, this should be an array of objects.
14980      * @param {Boolean} reset (optional) True to reset the template first
14981      * @return {MasterTemplate} this
14982      */
14983     fill : function(name, values, reset){
14984         var a = arguments;
14985         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
14986             values = a[0];
14987             name = 0;
14988             reset = a[1];
14989         }
14990         if(reset){
14991             this.reset();
14992         }
14993         for(var i = 0, len = values.length; i < len; i++){
14994             this.add(name, values[i]);
14995         }
14996         return this;
14997     },
14998
14999     /**
15000      * Resets the template for reuse
15001      * @return {MasterTemplate} this
15002      */
15003      reset : function(){
15004         var s = this.subs;
15005         for(var i = 0; i < this.subCount; i++){
15006             s[i].buffer = [];
15007         }
15008         return this;
15009     },
15010
15011     applyTemplate : function(values){
15012         var s = this.subs;
15013         var replaceIndex = -1;
15014         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
15015             return s[++replaceIndex].buffer.join("");
15016         });
15017         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
15018     },
15019
15020     apply : function(){
15021         return this.applyTemplate.apply(this, arguments);
15022     },
15023
15024     compile : function(){return this;}
15025 });
15026
15027 /**
15028  * Alias for fill().
15029  * @method
15030  */
15031 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
15032  /**
15033  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
15034  * var tpl = Roo.MasterTemplate.from('element-id');
15035  * @param {String/HTMLElement} el
15036  * @param {Object} config
15037  * @static
15038  */
15039 Roo.MasterTemplate.from = function(el, config){
15040     el = Roo.getDom(el);
15041     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
15042 };/*
15043  * Based on:
15044  * Ext JS Library 1.1.1
15045  * Copyright(c) 2006-2007, Ext JS, LLC.
15046  *
15047  * Originally Released Under LGPL - original licence link has changed is not relivant.
15048  *
15049  * Fork - LGPL
15050  * <script type="text/javascript">
15051  */
15052
15053  
15054 /**
15055  * @class Roo.util.CSS
15056  * Utility class for manipulating CSS rules
15057  * @static
15058
15059  */
15060 Roo.util.CSS = function(){
15061         var rules = null;
15062         var doc = document;
15063
15064     var camelRe = /(-[a-z])/gi;
15065     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
15066
15067    return {
15068    /**
15069     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
15070     * tag and appended to the HEAD of the document.
15071     * @param {String|Object} cssText The text containing the css rules
15072     * @param {String} id An id to add to the stylesheet for later removal
15073     * @return {StyleSheet}
15074     */
15075     createStyleSheet : function(cssText, id){
15076         var ss;
15077         var head = doc.getElementsByTagName("head")[0];
15078         var nrules = doc.createElement("style");
15079         nrules.setAttribute("type", "text/css");
15080         if(id){
15081             nrules.setAttribute("id", id);
15082         }
15083         if (typeof(cssText) != 'string') {
15084             // support object maps..
15085             // not sure if this a good idea.. 
15086             // perhaps it should be merged with the general css handling
15087             // and handle js style props.
15088             var cssTextNew = [];
15089             for(var n in cssText) {
15090                 var citems = [];
15091                 for(var k in cssText[n]) {
15092                     citems.push( k + ' : ' +cssText[n][k] + ';' );
15093                 }
15094                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
15095                 
15096             }
15097             cssText = cssTextNew.join("\n");
15098             
15099         }
15100        
15101        
15102        if(Roo.isIE){
15103            head.appendChild(nrules);
15104            ss = nrules.styleSheet;
15105            ss.cssText = cssText;
15106        }else{
15107            try{
15108                 nrules.appendChild(doc.createTextNode(cssText));
15109            }catch(e){
15110                nrules.cssText = cssText; 
15111            }
15112            head.appendChild(nrules);
15113            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
15114        }
15115        this.cacheStyleSheet(ss);
15116        return ss;
15117    },
15118
15119    /**
15120     * Removes a style or link tag by id
15121     * @param {String} id The id of the tag
15122     */
15123    removeStyleSheet : function(id){
15124        var existing = doc.getElementById(id);
15125        if(existing){
15126            existing.parentNode.removeChild(existing);
15127        }
15128    },
15129
15130    /**
15131     * Dynamically swaps an existing stylesheet reference for a new one
15132     * @param {String} id The id of an existing link tag to remove
15133     * @param {String} url The href of the new stylesheet to include
15134     */
15135    swapStyleSheet : function(id, url){
15136        this.removeStyleSheet(id);
15137        var ss = doc.createElement("link");
15138        ss.setAttribute("rel", "stylesheet");
15139        ss.setAttribute("type", "text/css");
15140        ss.setAttribute("id", id);
15141        ss.setAttribute("href", url);
15142        doc.getElementsByTagName("head")[0].appendChild(ss);
15143    },
15144    
15145    /**
15146     * Refresh the rule cache if you have dynamically added stylesheets
15147     * @return {Object} An object (hash) of rules indexed by selector
15148     */
15149    refreshCache : function(){
15150        return this.getRules(true);
15151    },
15152
15153    // private
15154    cacheStyleSheet : function(stylesheet){
15155        if(!rules){
15156            rules = {};
15157        }
15158        try{// try catch for cross domain access issue
15159            var ssRules = stylesheet.cssRules || stylesheet.rules;
15160            for(var j = ssRules.length-1; j >= 0; --j){
15161                rules[ssRules[j].selectorText] = ssRules[j];
15162            }
15163        }catch(e){}
15164    },
15165    
15166    /**
15167     * Gets all css rules for the document
15168     * @param {Boolean} refreshCache true to refresh the internal cache
15169     * @return {Object} An object (hash) of rules indexed by selector
15170     */
15171    getRules : function(refreshCache){
15172                 if(rules == null || refreshCache){
15173                         rules = {};
15174                         var ds = doc.styleSheets;
15175                         for(var i =0, len = ds.length; i < len; i++){
15176                             try{
15177                         this.cacheStyleSheet(ds[i]);
15178                     }catch(e){} 
15179                 }
15180                 }
15181                 return rules;
15182         },
15183         
15184         /**
15185     * Gets an an individual CSS rule by selector(s)
15186     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
15187     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
15188     * @return {CSSRule} The CSS rule or null if one is not found
15189     */
15190    getRule : function(selector, refreshCache){
15191                 var rs = this.getRules(refreshCache);
15192                 if(!(selector instanceof Array)){
15193                     return rs[selector];
15194                 }
15195                 for(var i = 0; i < selector.length; i++){
15196                         if(rs[selector[i]]){
15197                                 return rs[selector[i]];
15198                         }
15199                 }
15200                 return null;
15201         },
15202         
15203         
15204         /**
15205     * Updates a rule property
15206     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
15207     * @param {String} property The css property
15208     * @param {String} value The new value for the property
15209     * @return {Boolean} true If a rule was found and updated
15210     */
15211    updateRule : function(selector, property, value){
15212                 if(!(selector instanceof Array)){
15213                         var rule = this.getRule(selector);
15214                         if(rule){
15215                                 rule.style[property.replace(camelRe, camelFn)] = value;
15216                                 return true;
15217                         }
15218                 }else{
15219                         for(var i = 0; i < selector.length; i++){
15220                                 if(this.updateRule(selector[i], property, value)){
15221                                         return true;
15222                                 }
15223                         }
15224                 }
15225                 return false;
15226         }
15227    };   
15228 }();/*
15229  * Based on:
15230  * Ext JS Library 1.1.1
15231  * Copyright(c) 2006-2007, Ext JS, LLC.
15232  *
15233  * Originally Released Under LGPL - original licence link has changed is not relivant.
15234  *
15235  * Fork - LGPL
15236  * <script type="text/javascript">
15237  */
15238
15239  
15240
15241 /**
15242  * @class Roo.util.ClickRepeater
15243  * @extends Roo.util.Observable
15244  * 
15245  * A wrapper class which can be applied to any element. Fires a "click" event while the
15246  * mouse is pressed. The interval between firings may be specified in the config but
15247  * defaults to 10 milliseconds.
15248  * 
15249  * Optionally, a CSS class may be applied to the element during the time it is pressed.
15250  * 
15251  * @cfg {String/HTMLElement/Element} el The element to act as a button.
15252  * @cfg {Number} delay The initial delay before the repeating event begins firing.
15253  * Similar to an autorepeat key delay.
15254  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
15255  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
15256  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
15257  *           "interval" and "delay" are ignored. "immediate" is honored.
15258  * @cfg {Boolean} preventDefault True to prevent the default click event
15259  * @cfg {Boolean} stopDefault True to stop the default click event
15260  * 
15261  * @history
15262  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
15263  *     2007-02-02 jvs Renamed to ClickRepeater
15264  *   2007-02-03 jvs Modifications for FF Mac and Safari 
15265  *
15266  *  @constructor
15267  * @param {String/HTMLElement/Element} el The element to listen on
15268  * @param {Object} config
15269  **/
15270 Roo.util.ClickRepeater = function(el, config)
15271 {
15272     this.el = Roo.get(el);
15273     this.el.unselectable();
15274
15275     Roo.apply(this, config);
15276
15277     this.addEvents({
15278     /**
15279      * @event mousedown
15280      * Fires when the mouse button is depressed.
15281      * @param {Roo.util.ClickRepeater} this
15282      */
15283         "mousedown" : true,
15284     /**
15285      * @event click
15286      * Fires on a specified interval during the time the element is pressed.
15287      * @param {Roo.util.ClickRepeater} this
15288      */
15289         "click" : true,
15290     /**
15291      * @event mouseup
15292      * Fires when the mouse key is released.
15293      * @param {Roo.util.ClickRepeater} this
15294      */
15295         "mouseup" : true
15296     });
15297
15298     this.el.on("mousedown", this.handleMouseDown, this);
15299     if(this.preventDefault || this.stopDefault){
15300         this.el.on("click", function(e){
15301             if(this.preventDefault){
15302                 e.preventDefault();
15303             }
15304             if(this.stopDefault){
15305                 e.stopEvent();
15306             }
15307         }, this);
15308     }
15309
15310     // allow inline handler
15311     if(this.handler){
15312         this.on("click", this.handler,  this.scope || this);
15313     }
15314
15315     Roo.util.ClickRepeater.superclass.constructor.call(this);
15316 };
15317
15318 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
15319     interval : 20,
15320     delay: 250,
15321     preventDefault : true,
15322     stopDefault : false,
15323     timer : 0,
15324
15325     // private
15326     handleMouseDown : function(){
15327         clearTimeout(this.timer);
15328         this.el.blur();
15329         if(this.pressClass){
15330             this.el.addClass(this.pressClass);
15331         }
15332         this.mousedownTime = new Date();
15333
15334         Roo.get(document).on("mouseup", this.handleMouseUp, this);
15335         this.el.on("mouseout", this.handleMouseOut, this);
15336
15337         this.fireEvent("mousedown", this);
15338         this.fireEvent("click", this);
15339         
15340         this.timer = this.click.defer(this.delay || this.interval, this);
15341     },
15342
15343     // private
15344     click : function(){
15345         this.fireEvent("click", this);
15346         this.timer = this.click.defer(this.getInterval(), this);
15347     },
15348
15349     // private
15350     getInterval: function(){
15351         if(!this.accelerate){
15352             return this.interval;
15353         }
15354         var pressTime = this.mousedownTime.getElapsed();
15355         if(pressTime < 500){
15356             return 400;
15357         }else if(pressTime < 1700){
15358             return 320;
15359         }else if(pressTime < 2600){
15360             return 250;
15361         }else if(pressTime < 3500){
15362             return 180;
15363         }else if(pressTime < 4400){
15364             return 140;
15365         }else if(pressTime < 5300){
15366             return 80;
15367         }else if(pressTime < 6200){
15368             return 50;
15369         }else{
15370             return 10;
15371         }
15372     },
15373
15374     // private
15375     handleMouseOut : function(){
15376         clearTimeout(this.timer);
15377         if(this.pressClass){
15378             this.el.removeClass(this.pressClass);
15379         }
15380         this.el.on("mouseover", this.handleMouseReturn, this);
15381     },
15382
15383     // private
15384     handleMouseReturn : function(){
15385         this.el.un("mouseover", this.handleMouseReturn);
15386         if(this.pressClass){
15387             this.el.addClass(this.pressClass);
15388         }
15389         this.click();
15390     },
15391
15392     // private
15393     handleMouseUp : function(){
15394         clearTimeout(this.timer);
15395         this.el.un("mouseover", this.handleMouseReturn);
15396         this.el.un("mouseout", this.handleMouseOut);
15397         Roo.get(document).un("mouseup", this.handleMouseUp);
15398         this.el.removeClass(this.pressClass);
15399         this.fireEvent("mouseup", this);
15400     }
15401 });/**
15402  * @class Roo.util.Clipboard
15403  * @static
15404  * 
15405  * Clipboard UTILS
15406  * 
15407  **/
15408 Roo.util.Clipboard = {
15409     /**
15410      * Writes a string to the clipboard - using the Clipboard API if https, otherwise using text area.
15411      * @param {String} text to copy to clipboard
15412      */
15413     write : function(text) {
15414         // navigator clipboard api needs a secure context (https)
15415         if (navigator.clipboard && window.isSecureContext) {
15416             // navigator clipboard api method'
15417             navigator.clipboard.writeText(text);
15418             return ;
15419         } 
15420         // text area method
15421         var ta = document.createElement("textarea");
15422         ta.value = text;
15423         // make the textarea out of viewport
15424         ta.style.position = "fixed";
15425         ta.style.left = "-999999px";
15426         ta.style.top = "-999999px";
15427         document.body.appendChild(ta);
15428         ta.focus();
15429         ta.select();
15430         document.execCommand('copy');
15431         (function() {
15432             ta.remove();
15433         }).defer(100);
15434         
15435     }
15436         
15437 }
15438     /*
15439  * Based on:
15440  * Ext JS Library 1.1.1
15441  * Copyright(c) 2006-2007, Ext JS, LLC.
15442  *
15443  * Originally Released Under LGPL - original licence link has changed is not relivant.
15444  *
15445  * Fork - LGPL
15446  * <script type="text/javascript">
15447  */
15448
15449  
15450 /**
15451  * @class Roo.KeyNav
15452  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
15453  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
15454  * way to implement custom navigation schemes for any UI component.</p>
15455  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
15456  * pageUp, pageDown, del, home, end.  Usage:</p>
15457  <pre><code>
15458 var nav = new Roo.KeyNav("my-element", {
15459     "left" : function(e){
15460         this.moveLeft(e.ctrlKey);
15461     },
15462     "right" : function(e){
15463         this.moveRight(e.ctrlKey);
15464     },
15465     "enter" : function(e){
15466         this.save();
15467     },
15468     scope : this
15469 });
15470 </code></pre>
15471  * @constructor
15472  * @param {String/HTMLElement/Roo.Element} el The element to bind to
15473  * @param {Object} config The config
15474  */
15475 Roo.KeyNav = function(el, config){
15476     this.el = Roo.get(el);
15477     Roo.apply(this, config);
15478     if(!this.disabled){
15479         this.disabled = true;
15480         this.enable();
15481     }
15482 };
15483
15484 Roo.KeyNav.prototype = {
15485     /**
15486      * @cfg {Boolean} disabled
15487      * True to disable this KeyNav instance (defaults to false)
15488      */
15489     disabled : false,
15490     /**
15491      * @cfg {String} defaultEventAction
15492      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
15493      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
15494      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
15495      */
15496     defaultEventAction: "stopEvent",
15497     /**
15498      * @cfg {Boolean} forceKeyDown
15499      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
15500      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
15501      * handle keydown instead of keypress.
15502      */
15503     forceKeyDown : false,
15504
15505     // private
15506     prepareEvent : function(e){
15507         var k = e.getKey();
15508         var h = this.keyToHandler[k];
15509         //if(h && this[h]){
15510         //    e.stopPropagation();
15511         //}
15512         if(Roo.isSafari && h && k >= 37 && k <= 40){
15513             e.stopEvent();
15514         }
15515     },
15516
15517     // private
15518     relay : function(e){
15519         var k = e.getKey();
15520         var h = this.keyToHandler[k];
15521         if(h && this[h]){
15522             if(this.doRelay(e, this[h], h) !== true){
15523                 e[this.defaultEventAction]();
15524             }
15525         }
15526     },
15527
15528     // private
15529     doRelay : function(e, h, hname){
15530         return h.call(this.scope || this, e);
15531     },
15532
15533     // possible handlers
15534     enter : false,
15535     left : false,
15536     right : false,
15537     up : false,
15538     down : false,
15539     tab : false,
15540     esc : false,
15541     pageUp : false,
15542     pageDown : false,
15543     del : false,
15544     home : false,
15545     end : false,
15546
15547     // quick lookup hash
15548     keyToHandler : {
15549         37 : "left",
15550         39 : "right",
15551         38 : "up",
15552         40 : "down",
15553         33 : "pageUp",
15554         34 : "pageDown",
15555         46 : "del",
15556         36 : "home",
15557         35 : "end",
15558         13 : "enter",
15559         27 : "esc",
15560         9  : "tab"
15561     },
15562
15563         /**
15564          * Enable this KeyNav
15565          */
15566         enable: function(){
15567                 if(this.disabled){
15568             // ie won't do special keys on keypress, no one else will repeat keys with keydown
15569             // the EventObject will normalize Safari automatically
15570             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
15571                 this.el.on("keydown", this.relay,  this);
15572             }else{
15573                 this.el.on("keydown", this.prepareEvent,  this);
15574                 this.el.on("keypress", this.relay,  this);
15575             }
15576                     this.disabled = false;
15577                 }
15578         },
15579
15580         /**
15581          * Disable this KeyNav
15582          */
15583         disable: function(){
15584                 if(!this.disabled){
15585                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
15586                 this.el.un("keydown", this.relay);
15587             }else{
15588                 this.el.un("keydown", this.prepareEvent);
15589                 this.el.un("keypress", this.relay);
15590             }
15591                     this.disabled = true;
15592                 }
15593         }
15594 };/*
15595  * Based on:
15596  * Ext JS Library 1.1.1
15597  * Copyright(c) 2006-2007, Ext JS, LLC.
15598  *
15599  * Originally Released Under LGPL - original licence link has changed is not relivant.
15600  *
15601  * Fork - LGPL
15602  * <script type="text/javascript">
15603  */
15604
15605  
15606 /**
15607  * @class Roo.KeyMap
15608  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
15609  * The constructor accepts the same config object as defined by {@link #addBinding}.
15610  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
15611  * combination it will call the function with this signature (if the match is a multi-key
15612  * combination the callback will still be called only once): (String key, Roo.EventObject e)
15613  * A KeyMap can also handle a string representation of keys.<br />
15614  * Usage:
15615  <pre><code>
15616 // map one key by key code
15617 var map = new Roo.KeyMap("my-element", {
15618     key: 13, // or Roo.EventObject.ENTER
15619     fn: myHandler,
15620     scope: myObject
15621 });
15622
15623 // map multiple keys to one action by string
15624 var map = new Roo.KeyMap("my-element", {
15625     key: "a\r\n\t",
15626     fn: myHandler,
15627     scope: myObject
15628 });
15629
15630 // map multiple keys to multiple actions by strings and array of codes
15631 var map = new Roo.KeyMap("my-element", [
15632     {
15633         key: [10,13],
15634         fn: function(){ alert("Return was pressed"); }
15635     }, {
15636         key: "abc",
15637         fn: function(){ alert('a, b or c was pressed'); }
15638     }, {
15639         key: "\t",
15640         ctrl:true,
15641         shift:true,
15642         fn: function(){ alert('Control + shift + tab was pressed.'); }
15643     }
15644 ]);
15645 </code></pre>
15646  * <b>Note: A KeyMap starts enabled</b>
15647  * @constructor
15648  * @param {String/HTMLElement/Roo.Element} el The element to bind to
15649  * @param {Object} config The config (see {@link #addBinding})
15650  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
15651  */
15652 Roo.KeyMap = function(el, config, eventName){
15653     this.el  = Roo.get(el);
15654     this.eventName = eventName || "keydown";
15655     this.bindings = [];
15656     if(config){
15657         this.addBinding(config);
15658     }
15659     this.enable();
15660 };
15661
15662 Roo.KeyMap.prototype = {
15663     /**
15664      * True to stop the event from bubbling and prevent the default browser action if the
15665      * key was handled by the KeyMap (defaults to false)
15666      * @type Boolean
15667      */
15668     stopEvent : false,
15669
15670     /**
15671      * Add a new binding to this KeyMap. The following config object properties are supported:
15672      * <pre>
15673 Property    Type             Description
15674 ----------  ---------------  ----------------------------------------------------------------------
15675 key         String/Array     A single keycode or an array of keycodes to handle
15676 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
15677 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
15678 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
15679 fn          Function         The function to call when KeyMap finds the expected key combination
15680 scope       Object           The scope of the callback function
15681 </pre>
15682      *
15683      * Usage:
15684      * <pre><code>
15685 // Create a KeyMap
15686 var map = new Roo.KeyMap(document, {
15687     key: Roo.EventObject.ENTER,
15688     fn: handleKey,
15689     scope: this
15690 });
15691
15692 //Add a new binding to the existing KeyMap later
15693 map.addBinding({
15694     key: 'abc',
15695     shift: true,
15696     fn: handleKey,
15697     scope: this
15698 });
15699 </code></pre>
15700      * @param {Object/Array} config A single KeyMap config or an array of configs
15701      */
15702         addBinding : function(config){
15703         if(config instanceof Array){
15704             for(var i = 0, len = config.length; i < len; i++){
15705                 this.addBinding(config[i]);
15706             }
15707             return;
15708         }
15709         var keyCode = config.key,
15710             shift = config.shift, 
15711             ctrl = config.ctrl, 
15712             alt = config.alt,
15713             fn = config.fn,
15714             scope = config.scope;
15715         if(typeof keyCode == "string"){
15716             var ks = [];
15717             var keyString = keyCode.toUpperCase();
15718             for(var j = 0, len = keyString.length; j < len; j++){
15719                 ks.push(keyString.charCodeAt(j));
15720             }
15721             keyCode = ks;
15722         }
15723         var keyArray = keyCode instanceof Array;
15724         var handler = function(e){
15725             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
15726                 var k = e.getKey();
15727                 if(keyArray){
15728                     for(var i = 0, len = keyCode.length; i < len; i++){
15729                         if(keyCode[i] == k){
15730                           if(this.stopEvent){
15731                               e.stopEvent();
15732                           }
15733                           fn.call(scope || window, k, e);
15734                           return;
15735                         }
15736                     }
15737                 }else{
15738                     if(k == keyCode){
15739                         if(this.stopEvent){
15740                            e.stopEvent();
15741                         }
15742                         fn.call(scope || window, k, e);
15743                     }
15744                 }
15745             }
15746         };
15747         this.bindings.push(handler);  
15748         },
15749
15750     /**
15751      * Shorthand for adding a single key listener
15752      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
15753      * following options:
15754      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
15755      * @param {Function} fn The function to call
15756      * @param {Object} scope (optional) The scope of the function
15757      */
15758     on : function(key, fn, scope){
15759         var keyCode, shift, ctrl, alt;
15760         if(typeof key == "object" && !(key instanceof Array)){
15761             keyCode = key.key;
15762             shift = key.shift;
15763             ctrl = key.ctrl;
15764             alt = key.alt;
15765         }else{
15766             keyCode = key;
15767         }
15768         this.addBinding({
15769             key: keyCode,
15770             shift: shift,
15771             ctrl: ctrl,
15772             alt: alt,
15773             fn: fn,
15774             scope: scope
15775         })
15776     },
15777
15778     // private
15779     handleKeyDown : function(e){
15780             if(this.enabled){ //just in case
15781             var b = this.bindings;
15782             for(var i = 0, len = b.length; i < len; i++){
15783                 b[i].call(this, e);
15784             }
15785             }
15786         },
15787         
15788         /**
15789          * Returns true if this KeyMap is enabled
15790          * @return {Boolean} 
15791          */
15792         isEnabled : function(){
15793             return this.enabled;  
15794         },
15795         
15796         /**
15797          * Enables this KeyMap
15798          */
15799         enable: function(){
15800                 if(!this.enabled){
15801                     this.el.on(this.eventName, this.handleKeyDown, this);
15802                     this.enabled = true;
15803                 }
15804         },
15805
15806         /**
15807          * Disable this KeyMap
15808          */
15809         disable: function(){
15810                 if(this.enabled){
15811                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
15812                     this.enabled = false;
15813                 }
15814         }
15815 };/*
15816  * Based on:
15817  * Ext JS Library 1.1.1
15818  * Copyright(c) 2006-2007, Ext JS, LLC.
15819  *
15820  * Originally Released Under LGPL - original licence link has changed is not relivant.
15821  *
15822  * Fork - LGPL
15823  * <script type="text/javascript">
15824  */
15825
15826  
15827 /**
15828  * @class Roo.util.TextMetrics
15829  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
15830  * wide, in pixels, a given block of text will be.
15831  * @static
15832  */
15833 Roo.util.TextMetrics = function(){
15834     var shared;
15835     return {
15836         /**
15837          * Measures the size of the specified text
15838          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
15839          * that can affect the size of the rendered text
15840          * @param {String} text The text to measure
15841          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
15842          * in order to accurately measure the text height
15843          * @return {Object} An object containing the text's size {width: (width), height: (height)}
15844          */
15845         measure : function(el, text, fixedWidth){
15846             if(!shared){
15847                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
15848             }
15849             shared.bind(el);
15850             shared.setFixedWidth(fixedWidth || 'auto');
15851             return shared.getSize(text);
15852         },
15853
15854         /**
15855          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
15856          * the overhead of multiple calls to initialize the style properties on each measurement.
15857          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
15858          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
15859          * in order to accurately measure the text height
15860          * @return {Roo.util.TextMetrics.Instance} instance The new instance
15861          */
15862         createInstance : function(el, fixedWidth){
15863             return Roo.util.TextMetrics.Instance(el, fixedWidth);
15864         }
15865     };
15866 }();
15867
15868 /**
15869  * @class Roo.util.TextMetrics.Instance
15870  * Instance of  TextMetrics Calcuation
15871  * @constructor
15872  * Create a new TextMetrics Instance
15873  * @param {Object} bindto
15874  * @param {Boolean} fixedWidth
15875  */
15876
15877 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth)
15878 {
15879     var ml = new Roo.Element(document.createElement('div'));
15880     document.body.appendChild(ml.dom);
15881     ml.position('absolute');
15882     ml.setLeftTop(-1000, -1000);
15883     ml.hide();
15884
15885     if(fixedWidth){
15886         ml.setWidth(fixedWidth);
15887     }
15888      
15889     var instance = {
15890         /**
15891          * Returns the size of the specified text based on the internal element's style and width properties
15892          * @param {String} text The text to measure
15893          * @return {Object} An object containing the text's size {width: (width), height: (height)}
15894          */
15895         getSize : function(text){
15896             ml.update(text);
15897             var s = ml.getSize();
15898             ml.update('');
15899             return s;
15900         },
15901
15902         /**
15903          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
15904          * that can affect the size of the rendered text
15905          * @param {String/HTMLElement} el The element, dom node or id
15906          */
15907         bind : function(el){
15908             ml.setStyle(
15909                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
15910             );
15911         },
15912
15913         /**
15914          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
15915          * to set a fixed width in order to accurately measure the text height.
15916          * @param {Number} width The width to set on the element
15917          */
15918         setFixedWidth : function(width){
15919             ml.setWidth(width);
15920         },
15921
15922         /**
15923          * Returns the measured width of the specified text
15924          * @param {String} text The text to measure
15925          * @return {Number} width The width in pixels
15926          */
15927         getWidth : function(text){
15928             ml.dom.style.width = 'auto';
15929             return this.getSize(text).width;
15930         },
15931
15932         /**
15933          * Returns the measured height of the specified text.  For multiline text, be sure to call
15934          * {@link #setFixedWidth} if necessary.
15935          * @param {String} text The text to measure
15936          * @return {Number} height The height in pixels
15937          */
15938         getHeight : function(text){
15939             return this.getSize(text).height;
15940         }
15941     };
15942
15943     instance.bind(bindTo);
15944
15945     return instance;
15946 };
15947
15948 // backwards compat
15949 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
15950  * Based on:
15951  * Ext JS Library 1.1.1
15952  * Copyright(c) 2006-2007, Ext JS, LLC.
15953  *
15954  * Originally Released Under LGPL - original licence link has changed is not relivant.
15955  *
15956  * Fork - LGPL
15957  * <script type="text/javascript">
15958  */
15959
15960 /**
15961  * @class Roo.state.Provider
15962  * Abstract base class for state provider implementations. This class provides methods
15963  * for encoding and decoding <b>typed</b> variables including dates and defines the 
15964  * Provider interface.
15965  */
15966 Roo.state.Provider = function(){
15967     /**
15968      * @event statechange
15969      * Fires when a state change occurs.
15970      * @param {Provider} this This state provider
15971      * @param {String} key The state key which was changed
15972      * @param {String} value The encoded value for the state
15973      */
15974     this.addEvents({
15975         "statechange": true
15976     });
15977     this.state = {};
15978     Roo.state.Provider.superclass.constructor.call(this);
15979 };
15980 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
15981     /**
15982      * Returns the current value for a key
15983      * @param {String} name The key name
15984      * @param {Mixed} defaultValue A default value to return if the key's value is not found
15985      * @return {Mixed} The state data
15986      */
15987     get : function(name, defaultValue){
15988         return typeof this.state[name] == "undefined" ?
15989             defaultValue : this.state[name];
15990     },
15991     
15992     /**
15993      * Clears a value from the state
15994      * @param {String} name The key name
15995      */
15996     clear : function(name){
15997         delete this.state[name];
15998         this.fireEvent("statechange", this, name, null);
15999     },
16000     
16001     /**
16002      * Sets the value for a key
16003      * @param {String} name The key name
16004      * @param {Mixed} value The value to set
16005      */
16006     set : function(name, value){
16007         this.state[name] = value;
16008         this.fireEvent("statechange", this, name, value);
16009     },
16010     
16011     /**
16012      * Decodes a string previously encoded with {@link #encodeValue}.
16013      * @param {String} value The value to decode
16014      * @return {Mixed} The decoded value
16015      */
16016     decodeValue : function(cookie){
16017         var re = /^(a|n|d|b|s|o)\:(.*)$/;
16018         var matches = re.exec(unescape(cookie));
16019         if(!matches || !matches[1]) {
16020             return; // non state cookie
16021         }
16022         var type = matches[1];
16023         var v = matches[2];
16024         switch(type){
16025             case "n":
16026                 return parseFloat(v);
16027             case "d":
16028                 return new Date(Date.parse(v));
16029             case "b":
16030                 return (v == "1");
16031             case "a":
16032                 var all = [];
16033                 var values = v.split("^");
16034                 for(var i = 0, len = values.length; i < len; i++){
16035                     all.push(this.decodeValue(values[i]));
16036                 }
16037                 return all;
16038            case "o":
16039                 var all = {};
16040                 var values = v.split("^");
16041                 for(var i = 0, len = values.length; i < len; i++){
16042                     var kv = values[i].split("=");
16043                     all[kv[0]] = this.decodeValue(kv[1]);
16044                 }
16045                 return all;
16046            default:
16047                 return v;
16048         }
16049     },
16050     
16051     /**
16052      * Encodes a value including type information.  Decode with {@link #decodeValue}.
16053      * @param {Mixed} value The value to encode
16054      * @return {String} The encoded value
16055      */
16056     encodeValue : function(v){
16057         var enc;
16058         if(typeof v == "number"){
16059             enc = "n:" + v;
16060         }else if(typeof v == "boolean"){
16061             enc = "b:" + (v ? "1" : "0");
16062         }else if(v instanceof Date){
16063             enc = "d:" + v.toGMTString();
16064         }else if(v instanceof Array){
16065             var flat = "";
16066             for(var i = 0, len = v.length; i < len; i++){
16067                 flat += this.encodeValue(v[i]);
16068                 if(i != len-1) {
16069                     flat += "^";
16070                 }
16071             }
16072             enc = "a:" + flat;
16073         }else if(typeof v == "object"){
16074             var flat = "";
16075             for(var key in v){
16076                 if(typeof v[key] != "function"){
16077                     flat += key + "=" + this.encodeValue(v[key]) + "^";
16078                 }
16079             }
16080             enc = "o:" + flat.substring(0, flat.length-1);
16081         }else{
16082             enc = "s:" + v;
16083         }
16084         return escape(enc);        
16085     }
16086 });
16087
16088 /*
16089  * Based on:
16090  * Ext JS Library 1.1.1
16091  * Copyright(c) 2006-2007, Ext JS, LLC.
16092  *
16093  * Originally Released Under LGPL - original licence link has changed is not relivant.
16094  *
16095  * Fork - LGPL
16096  * <script type="text/javascript">
16097  */
16098 /**
16099  * @class Roo.state.Manager
16100  * This is the global state manager. By default all components that are "state aware" check this class
16101  * for state information if you don't pass them a custom state provider. In order for this class
16102  * to be useful, it must be initialized with a provider when your application initializes.
16103  <pre><code>
16104 // in your initialization function
16105 init : function(){
16106    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
16107    ...
16108    // supposed you have a {@link Roo.BorderLayout}
16109    var layout = new Roo.BorderLayout(...);
16110    layout.restoreState();
16111    // or a {Roo.BasicDialog}
16112    var dialog = new Roo.BasicDialog(...);
16113    dialog.restoreState();
16114  </code></pre>
16115  * @static
16116  */
16117 Roo.state.Manager = function(){
16118     var provider = new Roo.state.Provider();
16119     
16120     return {
16121         /**
16122          * Configures the default state provider for your application
16123          * @param {Provider} stateProvider The state provider to set
16124          */
16125         setProvider : function(stateProvider){
16126             provider = stateProvider;
16127         },
16128         
16129         /**
16130          * Returns the current value for a key
16131          * @param {String} name The key name
16132          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
16133          * @return {Mixed} The state data
16134          */
16135         get : function(key, defaultValue){
16136             return provider.get(key, defaultValue);
16137         },
16138         
16139         /**
16140          * Sets the value for a key
16141          * @param {String} name The key name
16142          * @param {Mixed} value The state data
16143          */
16144          set : function(key, value){
16145             provider.set(key, value);
16146         },
16147         
16148         /**
16149          * Clears a value from the state
16150          * @param {String} name The key name
16151          */
16152         clear : function(key){
16153             provider.clear(key);
16154         },
16155         
16156         /**
16157          * Gets the currently configured state provider
16158          * @return {Provider} The state provider
16159          */
16160         getProvider : function(){
16161             return provider;
16162         }
16163     };
16164 }();
16165 /*
16166  * Based on:
16167  * Ext JS Library 1.1.1
16168  * Copyright(c) 2006-2007, Ext JS, LLC.
16169  *
16170  * Originally Released Under LGPL - original licence link has changed is not relivant.
16171  *
16172  * Fork - LGPL
16173  * <script type="text/javascript">
16174  */
16175 /**
16176  * @class Roo.state.CookieProvider
16177  * @extends Roo.state.Provider
16178  * The default Provider implementation which saves state via cookies.
16179  * <br />Usage:
16180  <pre><code>
16181    var cp = new Roo.state.CookieProvider({
16182        path: "/cgi-bin/",
16183        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
16184        domain: "roojs.com"
16185    })
16186    Roo.state.Manager.setProvider(cp);
16187  </code></pre>
16188  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
16189  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
16190  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
16191  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
16192  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
16193  * domain the page is running on including the 'www' like 'www.roojs.com')
16194  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
16195  * @constructor
16196  * Create a new CookieProvider
16197  * @param {Object} config The configuration object
16198  */
16199 Roo.state.CookieProvider = function(config){
16200     Roo.state.CookieProvider.superclass.constructor.call(this);
16201     this.path = "/";
16202     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
16203     this.domain = null;
16204     this.secure = false;
16205     Roo.apply(this, config);
16206     this.state = this.readCookies();
16207 };
16208
16209 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
16210     // private
16211     set : function(name, value){
16212         if(typeof value == "undefined" || value === null){
16213             this.clear(name);
16214             return;
16215         }
16216         this.setCookie(name, value);
16217         Roo.state.CookieProvider.superclass.set.call(this, name, value);
16218     },
16219
16220     // private
16221     clear : function(name){
16222         this.clearCookie(name);
16223         Roo.state.CookieProvider.superclass.clear.call(this, name);
16224     },
16225
16226     // private
16227     readCookies : function(){
16228         var cookies = {};
16229         var c = document.cookie + ";";
16230         var re = /\s?(.*?)=(.*?);/g;
16231         var matches;
16232         while((matches = re.exec(c)) != null){
16233             var name = matches[1];
16234             var value = matches[2];
16235             if(name && name.substring(0,3) == "ys-"){
16236                 cookies[name.substr(3)] = this.decodeValue(value);
16237             }
16238         }
16239         return cookies;
16240     },
16241
16242     // private
16243     setCookie : function(name, value){
16244         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
16245            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
16246            ((this.path == null) ? "" : ("; path=" + this.path)) +
16247            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
16248            ((this.secure == true) ? "; secure" : "");
16249     },
16250
16251     // private
16252     clearCookie : function(name){
16253         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
16254            ((this.path == null) ? "" : ("; path=" + this.path)) +
16255            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
16256            ((this.secure == true) ? "; secure" : "");
16257     }
16258 });/*
16259  * Based on:
16260  * Ext JS Library 1.1.1
16261  * Copyright(c) 2006-2007, Ext JS, LLC.
16262  *
16263  * Originally Released Under LGPL - original licence link has changed is not relivant.
16264  *
16265  * Fork - LGPL
16266  * <script type="text/javascript">
16267  */
16268  
16269
16270 /**
16271  * @class Roo.ComponentMgr
16272  * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
16273  * @static
16274  */
16275 Roo.ComponentMgr = function(){
16276     var all = new Roo.util.MixedCollection();
16277
16278     return {
16279         /**
16280          * Registers a component.
16281          * @param {Roo.Component} c The component
16282          */
16283         register : function(c){
16284             all.add(c);
16285         },
16286
16287         /**
16288          * Unregisters a component.
16289          * @param {Roo.Component} c The component
16290          */
16291         unregister : function(c){
16292             all.remove(c);
16293         },
16294
16295         /**
16296          * Returns a component by id
16297          * @param {String} id The component id
16298          */
16299         get : function(id){
16300             return all.get(id);
16301         },
16302
16303         /**
16304          * Registers a function that will be called when a specified component is added to ComponentMgr
16305          * @param {String} id The component id
16306          * @param {Funtction} fn The callback function
16307          * @param {Object} scope The scope of the callback
16308          */
16309         onAvailable : function(id, fn, scope){
16310             all.on("add", function(index, o){
16311                 if(o.id == id){
16312                     fn.call(scope || o, o);
16313                     all.un("add", fn, scope);
16314                 }
16315             });
16316         }
16317     };
16318 }();/*
16319  * Based on:
16320  * Ext JS Library 1.1.1
16321  * Copyright(c) 2006-2007, Ext JS, LLC.
16322  *
16323  * Originally Released Under LGPL - original licence link has changed is not relivant.
16324  *
16325  * Fork - LGPL
16326  * <script type="text/javascript">
16327  */
16328  
16329 /**
16330  * @class Roo.Component
16331  * @extends Roo.util.Observable
16332  * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
16333  * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
16334  * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
16335  * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
16336  * All visual components (widgets) that require rendering into a layout should subclass Component.
16337  * @constructor
16338  * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
16339  * 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
16340  * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
16341  */
16342 Roo.Component = function(config){
16343     config = config || {};
16344     if(config.tagName || config.dom || typeof config == "string"){ // element object
16345         config = {el: config, id: config.id || config};
16346     }
16347     this.initialConfig = config;
16348
16349     Roo.apply(this, config);
16350     this.addEvents({
16351         /**
16352          * @event disable
16353          * Fires after the component is disabled.
16354              * @param {Roo.Component} this
16355              */
16356         disable : true,
16357         /**
16358          * @event enable
16359          * Fires after the component is enabled.
16360              * @param {Roo.Component} this
16361              */
16362         enable : true,
16363         /**
16364          * @event beforeshow
16365          * Fires before the component is shown.  Return false to stop the show.
16366              * @param {Roo.Component} this
16367              */
16368         beforeshow : true,
16369         /**
16370          * @event show
16371          * Fires after the component is shown.
16372              * @param {Roo.Component} this
16373              */
16374         show : true,
16375         /**
16376          * @event beforehide
16377          * Fires before the component is hidden. Return false to stop the hide.
16378              * @param {Roo.Component} this
16379              */
16380         beforehide : true,
16381         /**
16382          * @event hide
16383          * Fires after the component is hidden.
16384              * @param {Roo.Component} this
16385              */
16386         hide : true,
16387         /**
16388          * @event beforerender
16389          * Fires before the component is rendered. Return false to stop the render.
16390              * @param {Roo.Component} this
16391              */
16392         beforerender : true,
16393         /**
16394          * @event render
16395          * Fires after the component is rendered.
16396              * @param {Roo.Component} this
16397              */
16398         render : true,
16399         /**
16400          * @event beforedestroy
16401          * Fires before the component is destroyed. Return false to stop the destroy.
16402              * @param {Roo.Component} this
16403              */
16404         beforedestroy : true,
16405         /**
16406          * @event destroy
16407          * Fires after the component is destroyed.
16408              * @param {Roo.Component} this
16409              */
16410         destroy : true
16411     });
16412     if(!this.id){
16413         this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
16414     }
16415     Roo.ComponentMgr.register(this);
16416     Roo.Component.superclass.constructor.call(this);
16417     this.initComponent();
16418     if(this.renderTo){ // not supported by all components yet. use at your own risk!
16419         this.render(this.renderTo);
16420         delete this.renderTo;
16421     }
16422 };
16423
16424 /** @private */
16425 Roo.Component.AUTO_ID = 1000;
16426
16427 Roo.extend(Roo.Component, Roo.util.Observable, {
16428     /**
16429      * @scope Roo.Component.prototype
16430      * @type {Boolean}
16431      * true if this component is hidden. Read-only.
16432      */
16433     hidden : false,
16434     /**
16435      * @type {Boolean}
16436      * true if this component is disabled. Read-only.
16437      */
16438     disabled : false,
16439     /**
16440      * @type {Boolean}
16441      * true if this component has been rendered. Read-only.
16442      */
16443     rendered : false,
16444     
16445     /** @cfg {String} disableClass
16446      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
16447      */
16448     disabledClass : "x-item-disabled",
16449         /** @cfg {Boolean} allowDomMove
16450          * Whether the component can move the Dom node when rendering (defaults to true).
16451          */
16452     allowDomMove : true,
16453     /** @cfg {String} hideMode (display|visibility)
16454      * How this component should hidden. Supported values are
16455      * "visibility" (css visibility), "offsets" (negative offset position) and
16456      * "display" (css display) - defaults to "display".
16457      */
16458     hideMode: 'display',
16459
16460     /** @private */
16461     ctype : "Roo.Component",
16462
16463     /**
16464      * @cfg {String} actionMode 
16465      * which property holds the element that used for  hide() / show() / disable() / enable()
16466      * default is 'el' for forms you probably want to set this to fieldEl 
16467      */
16468     actionMode : "el",
16469
16470     /** @private */
16471     getActionEl : function(){
16472         return this[this.actionMode];
16473     },
16474
16475     initComponent : Roo.emptyFn,
16476     /**
16477      * If this is a lazy rendering component, render it to its container element.
16478      * @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.
16479      */
16480     render : function(container, position){
16481         
16482         if(this.rendered){
16483             return this;
16484         }
16485         
16486         if(this.fireEvent("beforerender", this) === false){
16487             return false;
16488         }
16489         
16490         if(!container && this.el){
16491             this.el = Roo.get(this.el);
16492             container = this.el.dom.parentNode;
16493             this.allowDomMove = false;
16494         }
16495         this.container = Roo.get(container);
16496         this.rendered = true;
16497         if(position !== undefined){
16498             if(typeof position == 'number'){
16499                 position = this.container.dom.childNodes[position];
16500             }else{
16501                 position = Roo.getDom(position);
16502             }
16503         }
16504         this.onRender(this.container, position || null);
16505         if(this.cls){
16506             this.el.addClass(this.cls);
16507             delete this.cls;
16508         }
16509         if(this.style){
16510             this.el.applyStyles(this.style);
16511             delete this.style;
16512         }
16513         this.fireEvent("render", this);
16514         this.afterRender(this.container);
16515         if(this.hidden){
16516             this.hide();
16517         }
16518         if(this.disabled){
16519             this.disable();
16520         }
16521
16522         return this;
16523         
16524     },
16525
16526     /** @private */
16527     // default function is not really useful
16528     onRender : function(ct, position){
16529         if(this.el){
16530             this.el = Roo.get(this.el);
16531             if(this.allowDomMove !== false){
16532                 ct.dom.insertBefore(this.el.dom, position);
16533             }
16534         }
16535     },
16536
16537     /** @private */
16538     getAutoCreate : function(){
16539         var cfg = typeof this.autoCreate == "object" ?
16540                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
16541         if(this.id && !cfg.id){
16542             cfg.id = this.id;
16543         }
16544         return cfg;
16545     },
16546
16547     /** @private */
16548     afterRender : Roo.emptyFn,
16549
16550     /**
16551      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
16552      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
16553      */
16554     destroy : function(){
16555         if(this.fireEvent("beforedestroy", this) !== false){
16556             this.purgeListeners();
16557             this.beforeDestroy();
16558             if(this.rendered){
16559                 this.el.removeAllListeners();
16560                 this.el.remove();
16561                 if(this.actionMode == "container"){
16562                     this.container.remove();
16563                 }
16564             }
16565             this.onDestroy();
16566             Roo.ComponentMgr.unregister(this);
16567             this.fireEvent("destroy", this);
16568         }
16569     },
16570
16571         /** @private */
16572     beforeDestroy : function(){
16573
16574     },
16575
16576         /** @private */
16577         onDestroy : function(){
16578
16579     },
16580
16581     /**
16582      * Returns the underlying {@link Roo.Element}.
16583      * @return {Roo.Element} The element
16584      */
16585     getEl : function(){
16586         return this.el;
16587     },
16588
16589     /**
16590      * Returns the id of this component.
16591      * @return {String}
16592      */
16593     getId : function(){
16594         return this.id;
16595     },
16596
16597     /**
16598      * Try to focus this component.
16599      * @param {Boolean} selectText True to also select the text in this component (if applicable)
16600      * @return {Roo.Component} this
16601      */
16602     focus : function(selectText){
16603         if(this.rendered){
16604             this.el.focus();
16605             if(selectText === true){
16606                 this.el.dom.select();
16607             }
16608         }
16609         return this;
16610     },
16611
16612     /** @private */
16613     blur : function(){
16614         if(this.rendered){
16615             this.el.blur();
16616         }
16617         return this;
16618     },
16619
16620     /**
16621      * Disable this component.
16622      * @return {Roo.Component} this
16623      */
16624     disable : function(){
16625         if(this.rendered){
16626             this.onDisable();
16627         }
16628         this.disabled = true;
16629         this.fireEvent("disable", this);
16630         return this;
16631     },
16632
16633         // private
16634     onDisable : function(){
16635         this.getActionEl().addClass(this.disabledClass);
16636         this.el.dom.disabled = true;
16637     },
16638
16639     /**
16640      * Enable this component.
16641      * @return {Roo.Component} this
16642      */
16643     enable : function(){
16644         if(this.rendered){
16645             this.onEnable();
16646         }
16647         this.disabled = false;
16648         this.fireEvent("enable", this);
16649         return this;
16650     },
16651
16652         // private
16653     onEnable : function(){
16654         this.getActionEl().removeClass(this.disabledClass);
16655         this.el.dom.disabled = false;
16656     },
16657
16658     /**
16659      * Convenience function for setting disabled/enabled by boolean.
16660      * @param {Boolean} disabled
16661      */
16662     setDisabled : function(disabled){
16663         this[disabled ? "disable" : "enable"]();
16664     },
16665
16666     /**
16667      * Show this component.
16668      * @return {Roo.Component} this
16669      */
16670     show: function(){
16671         if(this.fireEvent("beforeshow", this) !== false){
16672             this.hidden = false;
16673             if(this.rendered){
16674                 this.onShow();
16675             }
16676             this.fireEvent("show", this);
16677         }
16678         return this;
16679     },
16680
16681     // private
16682     onShow : function(){
16683         var ae = this.getActionEl();
16684         if(this.hideMode == 'visibility'){
16685             ae.dom.style.visibility = "visible";
16686         }else if(this.hideMode == 'offsets'){
16687             ae.removeClass('x-hidden');
16688         }else{
16689             ae.dom.style.display = "";
16690         }
16691     },
16692
16693     /**
16694      * Hide this component.
16695      * @return {Roo.Component} this
16696      */
16697     hide: function(){
16698         if(this.fireEvent("beforehide", this) !== false){
16699             this.hidden = true;
16700             if(this.rendered){
16701                 this.onHide();
16702             }
16703             this.fireEvent("hide", this);
16704         }
16705         return this;
16706     },
16707
16708     // private
16709     onHide : function(){
16710         var ae = this.getActionEl();
16711         if(this.hideMode == 'visibility'){
16712             ae.dom.style.visibility = "hidden";
16713         }else if(this.hideMode == 'offsets'){
16714             ae.addClass('x-hidden');
16715         }else{
16716             ae.dom.style.display = "none";
16717         }
16718     },
16719
16720     /**
16721      * Convenience function to hide or show this component by boolean.
16722      * @param {Boolean} visible True to show, false to hide
16723      * @return {Roo.Component} this
16724      */
16725     setVisible: function(visible){
16726         if(visible) {
16727             this.show();
16728         }else{
16729             this.hide();
16730         }
16731         return this;
16732     },
16733
16734     /**
16735      * Returns true if this component is visible.
16736      */
16737     isVisible : function(){
16738         return this.getActionEl().isVisible();
16739     },
16740
16741     cloneConfig : function(overrides){
16742         overrides = overrides || {};
16743         var id = overrides.id || Roo.id();
16744         var cfg = Roo.applyIf(overrides, this.initialConfig);
16745         cfg.id = id; // prevent dup id
16746         return new this.constructor(cfg);
16747     }
16748 });/*
16749  * Based on:
16750  * Ext JS Library 1.1.1
16751  * Copyright(c) 2006-2007, Ext JS, LLC.
16752  *
16753  * Originally Released Under LGPL - original licence link has changed is not relivant.
16754  *
16755  * Fork - LGPL
16756  * <script type="text/javascript">
16757  */
16758
16759 /**
16760  * @class Roo.BoxComponent
16761  * @extends Roo.Component
16762  * Base class for any visual {@link Roo.Component} that uses a box container.  BoxComponent provides automatic box
16763  * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model.  All
16764  * container classes should subclass BoxComponent so that they will work consistently when nested within other Roo
16765  * layout containers.
16766  * @constructor
16767  * @param {Roo.Element/String/Object} config The configuration options.
16768  */
16769 Roo.BoxComponent = function(config){
16770     Roo.Component.call(this, config);
16771     this.addEvents({
16772         /**
16773          * @event resize
16774          * Fires after the component is resized.
16775              * @param {Roo.Component} this
16776              * @param {Number} adjWidth The box-adjusted width that was set
16777              * @param {Number} adjHeight The box-adjusted height that was set
16778              * @param {Number} rawWidth The width that was originally specified
16779              * @param {Number} rawHeight The height that was originally specified
16780              */
16781         resize : true,
16782         /**
16783          * @event move
16784          * Fires after the component is moved.
16785              * @param {Roo.Component} this
16786              * @param {Number} x The new x position
16787              * @param {Number} y The new y position
16788              */
16789         move : true
16790     });
16791 };
16792
16793 Roo.extend(Roo.BoxComponent, Roo.Component, {
16794     // private, set in afterRender to signify that the component has been rendered
16795     boxReady : false,
16796     // private, used to defer height settings to subclasses
16797     deferHeight: false,
16798     /** @cfg {Number} width
16799      * width (optional) size of component
16800      */
16801      /** @cfg {Number} height
16802      * height (optional) size of component
16803      */
16804      
16805     /**
16806      * Sets the width and height of the component.  This method fires the resize event.  This method can accept
16807      * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
16808      * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
16809      * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
16810      * @return {Roo.BoxComponent} this
16811      */
16812     setSize : function(w, h){
16813         // support for standard size objects
16814         if(typeof w == 'object'){
16815             h = w.height;
16816             w = w.width;
16817         }
16818         // not rendered
16819         if(!this.boxReady){
16820             this.width = w;
16821             this.height = h;
16822             return this;
16823         }
16824
16825         // prevent recalcs when not needed
16826         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
16827             return this;
16828         }
16829         this.lastSize = {width: w, height: h};
16830
16831         var adj = this.adjustSize(w, h);
16832         var aw = adj.width, ah = adj.height;
16833         if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
16834             var rz = this.getResizeEl();
16835             if(!this.deferHeight && aw !== undefined && ah !== undefined){
16836                 rz.setSize(aw, ah);
16837             }else if(!this.deferHeight && ah !== undefined){
16838                 rz.setHeight(ah);
16839             }else if(aw !== undefined){
16840                 rz.setWidth(aw);
16841             }
16842             this.onResize(aw, ah, w, h);
16843             this.fireEvent('resize', this, aw, ah, w, h);
16844         }
16845         return this;
16846     },
16847
16848     /**
16849      * Gets the current size of the component's underlying element.
16850      * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
16851      */
16852     getSize : function(){
16853         return this.el.getSize();
16854     },
16855
16856     /**
16857      * Gets the current XY position of the component's underlying element.
16858      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
16859      * @return {Array} The XY position of the element (e.g., [100, 200])
16860      */
16861     getPosition : function(local){
16862         if(local === true){
16863             return [this.el.getLeft(true), this.el.getTop(true)];
16864         }
16865         return this.xy || this.el.getXY();
16866     },
16867
16868     /**
16869      * Gets the current box measurements of the component's underlying element.
16870      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
16871      * @returns {Object} box An object in the format {x, y, width, height}
16872      */
16873     getBox : function(local){
16874         var s = this.el.getSize();
16875         if(local){
16876             s.x = this.el.getLeft(true);
16877             s.y = this.el.getTop(true);
16878         }else{
16879             var xy = this.xy || this.el.getXY();
16880             s.x = xy[0];
16881             s.y = xy[1];
16882         }
16883         return s;
16884     },
16885
16886     /**
16887      * Sets the current box measurements of the component's underlying element.
16888      * @param {Object} box An object in the format {x, y, width, height}
16889      * @returns {Roo.BoxComponent} this
16890      */
16891     updateBox : function(box){
16892         this.setSize(box.width, box.height);
16893         this.setPagePosition(box.x, box.y);
16894         return this;
16895     },
16896
16897     // protected
16898     getResizeEl : function(){
16899         return this.resizeEl || this.el;
16900     },
16901
16902     // protected
16903     getPositionEl : function(){
16904         return this.positionEl || this.el;
16905     },
16906
16907     /**
16908      * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
16909      * This method fires the move event.
16910      * @param {Number} left The new left
16911      * @param {Number} top The new top
16912      * @returns {Roo.BoxComponent} this
16913      */
16914     setPosition : function(x, y){
16915         this.x = x;
16916         this.y = y;
16917         if(!this.boxReady){
16918             return this;
16919         }
16920         var adj = this.adjustPosition(x, y);
16921         var ax = adj.x, ay = adj.y;
16922
16923         var el = this.getPositionEl();
16924         if(ax !== undefined || ay !== undefined){
16925             if(ax !== undefined && ay !== undefined){
16926                 el.setLeftTop(ax, ay);
16927             }else if(ax !== undefined){
16928                 el.setLeft(ax);
16929             }else if(ay !== undefined){
16930                 el.setTop(ay);
16931             }
16932             this.onPosition(ax, ay);
16933             this.fireEvent('move', this, ax, ay);
16934         }
16935         return this;
16936     },
16937
16938     /**
16939      * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
16940      * This method fires the move event.
16941      * @param {Number} x The new x position
16942      * @param {Number} y The new y position
16943      * @returns {Roo.BoxComponent} this
16944      */
16945     setPagePosition : function(x, y){
16946         this.pageX = x;
16947         this.pageY = y;
16948         if(!this.boxReady){
16949             return;
16950         }
16951         if(x === undefined || y === undefined){ // cannot translate undefined points
16952             return;
16953         }
16954         var p = this.el.translatePoints(x, y);
16955         this.setPosition(p.left, p.top);
16956         return this;
16957     },
16958
16959     // private
16960     onRender : function(ct, position){
16961         Roo.BoxComponent.superclass.onRender.call(this, ct, position);
16962         if(this.resizeEl){
16963             this.resizeEl = Roo.get(this.resizeEl);
16964         }
16965         if(this.positionEl){
16966             this.positionEl = Roo.get(this.positionEl);
16967         }
16968     },
16969
16970     // private
16971     afterRender : function(){
16972         Roo.BoxComponent.superclass.afterRender.call(this);
16973         this.boxReady = true;
16974         this.setSize(this.width, this.height);
16975         if(this.x || this.y){
16976             this.setPosition(this.x, this.y);
16977         }
16978         if(this.pageX || this.pageY){
16979             this.setPagePosition(this.pageX, this.pageY);
16980         }
16981     },
16982
16983     /**
16984      * Force the component's size to recalculate based on the underlying element's current height and width.
16985      * @returns {Roo.BoxComponent} this
16986      */
16987     syncSize : function(){
16988         delete this.lastSize;
16989         this.setSize(this.el.getWidth(), this.el.getHeight());
16990         return this;
16991     },
16992
16993     /**
16994      * Called after the component is resized, this method is empty by default but can be implemented by any
16995      * subclass that needs to perform custom logic after a resize occurs.
16996      * @param {Number} adjWidth The box-adjusted width that was set
16997      * @param {Number} adjHeight The box-adjusted height that was set
16998      * @param {Number} rawWidth The width that was originally specified
16999      * @param {Number} rawHeight The height that was originally specified
17000      */
17001     onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
17002
17003     },
17004
17005     /**
17006      * Called after the component is moved, this method is empty by default but can be implemented by any
17007      * subclass that needs to perform custom logic after a move occurs.
17008      * @param {Number} x The new x position
17009      * @param {Number} y The new y position
17010      */
17011     onPosition : function(x, y){
17012
17013     },
17014
17015     // private
17016     adjustSize : function(w, h){
17017         if(this.autoWidth){
17018             w = 'auto';
17019         }
17020         if(this.autoHeight){
17021             h = 'auto';
17022         }
17023         return {width : w, height: h};
17024     },
17025
17026     // private
17027     adjustPosition : function(x, y){
17028         return {x : x, y: y};
17029     }
17030 });/*
17031  * Based on:
17032  * Ext JS Library 1.1.1
17033  * Copyright(c) 2006-2007, Ext JS, LLC.
17034  *
17035  * Originally Released Under LGPL - original licence link has changed is not relivant.
17036  *
17037  * Fork - LGPL
17038  * <script type="text/javascript">
17039  */
17040  (function(){ 
17041 /**
17042  * @class Roo.Layer
17043  * @extends Roo.Element
17044  * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
17045  * automatic maintaining of shadow/shim positions.
17046  * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
17047  * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
17048  * you can pass a string with a CSS class name. False turns off the shadow.
17049  * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
17050  * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
17051  * @cfg {String} cls CSS class to add to the element
17052  * @cfg {Number} zindex Starting z-index (defaults to 11000)
17053  * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
17054  * @constructor
17055  * @param {Object} config An object with config options.
17056  * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
17057  */
17058
17059 Roo.Layer = function(config, existingEl){
17060     config = config || {};
17061     var dh = Roo.DomHelper;
17062     var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
17063     if(existingEl){
17064         this.dom = Roo.getDom(existingEl);
17065     }
17066     if(!this.dom){
17067         var o = config.dh || {tag: "div", cls: "x-layer"};
17068         this.dom = dh.append(pel, o);
17069     }
17070     if(config.cls){
17071         this.addClass(config.cls);
17072     }
17073     this.constrain = config.constrain !== false;
17074     this.visibilityMode = Roo.Element.VISIBILITY;
17075     if(config.id){
17076         this.id = this.dom.id = config.id;
17077     }else{
17078         this.id = Roo.id(this.dom);
17079     }
17080     this.zindex = config.zindex || this.getZIndex();
17081     this.position("absolute", this.zindex);
17082     if(config.shadow){
17083         this.shadowOffset = config.shadowOffset || 4;
17084         this.shadow = new Roo.Shadow({
17085             offset : this.shadowOffset,
17086             mode : config.shadow
17087         });
17088     }else{
17089         this.shadowOffset = 0;
17090     }
17091     this.useShim = config.shim !== false && Roo.useShims;
17092     this.useDisplay = config.useDisplay;
17093     this.hide();
17094 };
17095
17096 var supr = Roo.Element.prototype;
17097
17098 // shims are shared among layer to keep from having 100 iframes
17099 var shims = [];
17100
17101 Roo.extend(Roo.Layer, Roo.Element, {
17102
17103     getZIndex : function(){
17104         return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
17105     },
17106
17107     getShim : function(){
17108         if(!this.useShim){
17109             return null;
17110         }
17111         if(this.shim){
17112             return this.shim;
17113         }
17114         var shim = shims.shift();
17115         if(!shim){
17116             shim = this.createShim();
17117             shim.enableDisplayMode('block');
17118             shim.dom.style.display = 'none';
17119             shim.dom.style.visibility = 'visible';
17120         }
17121         var pn = this.dom.parentNode;
17122         if(shim.dom.parentNode != pn){
17123             pn.insertBefore(shim.dom, this.dom);
17124         }
17125         shim.setStyle('z-index', this.getZIndex()-2);
17126         this.shim = shim;
17127         return shim;
17128     },
17129
17130     hideShim : function(){
17131         if(this.shim){
17132             this.shim.setDisplayed(false);
17133             shims.push(this.shim);
17134             delete this.shim;
17135         }
17136     },
17137
17138     disableShadow : function(){
17139         if(this.shadow){
17140             this.shadowDisabled = true;
17141             this.shadow.hide();
17142             this.lastShadowOffset = this.shadowOffset;
17143             this.shadowOffset = 0;
17144         }
17145     },
17146
17147     enableShadow : function(show){
17148         if(this.shadow){
17149             this.shadowDisabled = false;
17150             this.shadowOffset = this.lastShadowOffset;
17151             delete this.lastShadowOffset;
17152             if(show){
17153                 this.sync(true);
17154             }
17155         }
17156     },
17157
17158     // private
17159     // this code can execute repeatedly in milliseconds (i.e. during a drag) so
17160     // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
17161     sync : function(doShow){
17162         var sw = this.shadow;
17163         if(!this.updating && this.isVisible() && (sw || this.useShim)){
17164             var sh = this.getShim();
17165
17166             var w = this.getWidth(),
17167                 h = this.getHeight();
17168
17169             var l = this.getLeft(true),
17170                 t = this.getTop(true);
17171
17172             if(sw && !this.shadowDisabled){
17173                 if(doShow && !sw.isVisible()){
17174                     sw.show(this);
17175                 }else{
17176                     sw.realign(l, t, w, h);
17177                 }
17178                 if(sh){
17179                     if(doShow){
17180                        sh.show();
17181                     }
17182                     // fit the shim behind the shadow, so it is shimmed too
17183                     var a = sw.adjusts, s = sh.dom.style;
17184                     s.left = (Math.min(l, l+a.l))+"px";
17185                     s.top = (Math.min(t, t+a.t))+"px";
17186                     s.width = (w+a.w)+"px";
17187                     s.height = (h+a.h)+"px";
17188                 }
17189             }else if(sh){
17190                 if(doShow){
17191                    sh.show();
17192                 }
17193                 sh.setSize(w, h);
17194                 sh.setLeftTop(l, t);
17195             }
17196             
17197         }
17198     },
17199
17200     // private
17201     destroy : function(){
17202         this.hideShim();
17203         if(this.shadow){
17204             this.shadow.hide();
17205         }
17206         this.removeAllListeners();
17207         var pn = this.dom.parentNode;
17208         if(pn){
17209             pn.removeChild(this.dom);
17210         }
17211         Roo.Element.uncache(this.id);
17212     },
17213
17214     remove : function(){
17215         this.destroy();
17216     },
17217
17218     // private
17219     beginUpdate : function(){
17220         this.updating = true;
17221     },
17222
17223     // private
17224     endUpdate : function(){
17225         this.updating = false;
17226         this.sync(true);
17227     },
17228
17229     // private
17230     hideUnders : function(negOffset){
17231         if(this.shadow){
17232             this.shadow.hide();
17233         }
17234         this.hideShim();
17235     },
17236
17237     // private
17238     constrainXY : function(){
17239         if(this.constrain){
17240             var vw = Roo.lib.Dom.getViewWidth(),
17241                 vh = Roo.lib.Dom.getViewHeight();
17242             var s = Roo.get(document).getScroll();
17243
17244             var xy = this.getXY();
17245             var x = xy[0], y = xy[1];   
17246             var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
17247             // only move it if it needs it
17248             var moved = false;
17249             // first validate right/bottom
17250             if((x + w) > vw+s.left){
17251                 x = vw - w - this.shadowOffset;
17252                 moved = true;
17253             }
17254             if((y + h) > vh+s.top){
17255                 y = vh - h - this.shadowOffset;
17256                 moved = true;
17257             }
17258             // then make sure top/left isn't negative
17259             if(x < s.left){
17260                 x = s.left;
17261                 moved = true;
17262             }
17263             if(y < s.top){
17264                 y = s.top;
17265                 moved = true;
17266             }
17267             if(moved){
17268                 if(this.avoidY){
17269                     var ay = this.avoidY;
17270                     if(y <= ay && (y+h) >= ay){
17271                         y = ay-h-5;   
17272                     }
17273                 }
17274                 xy = [x, y];
17275                 this.storeXY(xy);
17276                 supr.setXY.call(this, xy);
17277                 this.sync();
17278             }
17279         }
17280     },
17281
17282     isVisible : function(){
17283         return this.visible;    
17284     },
17285
17286     // private
17287     showAction : function(){
17288         this.visible = true; // track visibility to prevent getStyle calls
17289         if(this.useDisplay === true){
17290             this.setDisplayed("");
17291         }else if(this.lastXY){
17292             supr.setXY.call(this, this.lastXY);
17293         }else if(this.lastLT){
17294             supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
17295         }
17296     },
17297
17298     // private
17299     hideAction : function(){
17300         this.visible = false;
17301         if(this.useDisplay === true){
17302             this.setDisplayed(false);
17303         }else{
17304             this.setLeftTop(-10000,-10000);
17305         }
17306     },
17307
17308     // overridden Element method
17309     setVisible : function(v, a, d, c, e){
17310         if(v){
17311             this.showAction();
17312         }
17313         if(a && v){
17314             var cb = function(){
17315                 this.sync(true);
17316                 if(c){
17317                     c();
17318                 }
17319             }.createDelegate(this);
17320             supr.setVisible.call(this, true, true, d, cb, e);
17321         }else{
17322             if(!v){
17323                 this.hideUnders(true);
17324             }
17325             var cb = c;
17326             if(a){
17327                 cb = function(){
17328                     this.hideAction();
17329                     if(c){
17330                         c();
17331                     }
17332                 }.createDelegate(this);
17333             }
17334             supr.setVisible.call(this, v, a, d, cb, e);
17335             if(v){
17336                 this.sync(true);
17337             }else if(!a){
17338                 this.hideAction();
17339             }
17340         }
17341     },
17342
17343     storeXY : function(xy){
17344         delete this.lastLT;
17345         this.lastXY = xy;
17346     },
17347
17348     storeLeftTop : function(left, top){
17349         delete this.lastXY;
17350         this.lastLT = [left, top];
17351     },
17352
17353     // private
17354     beforeFx : function(){
17355         this.beforeAction();
17356         return Roo.Layer.superclass.beforeFx.apply(this, arguments);
17357     },
17358
17359     // private
17360     afterFx : function(){
17361         Roo.Layer.superclass.afterFx.apply(this, arguments);
17362         this.sync(this.isVisible());
17363     },
17364
17365     // private
17366     beforeAction : function(){
17367         if(!this.updating && this.shadow){
17368             this.shadow.hide();
17369         }
17370     },
17371
17372     // overridden Element method
17373     setLeft : function(left){
17374         this.storeLeftTop(left, this.getTop(true));
17375         supr.setLeft.apply(this, arguments);
17376         this.sync();
17377     },
17378
17379     setTop : function(top){
17380         this.storeLeftTop(this.getLeft(true), top);
17381         supr.setTop.apply(this, arguments);
17382         this.sync();
17383     },
17384
17385     setLeftTop : function(left, top){
17386         this.storeLeftTop(left, top);
17387         supr.setLeftTop.apply(this, arguments);
17388         this.sync();
17389     },
17390
17391     setXY : function(xy, a, d, c, e){
17392         this.fixDisplay();
17393         this.beforeAction();
17394         this.storeXY(xy);
17395         var cb = this.createCB(c);
17396         supr.setXY.call(this, xy, a, d, cb, e);
17397         if(!a){
17398             cb();
17399         }
17400     },
17401
17402     // private
17403     createCB : function(c){
17404         var el = this;
17405         return function(){
17406             el.constrainXY();
17407             el.sync(true);
17408             if(c){
17409                 c();
17410             }
17411         };
17412     },
17413
17414     // overridden Element method
17415     setX : function(x, a, d, c, e){
17416         this.setXY([x, this.getY()], a, d, c, e);
17417     },
17418
17419     // overridden Element method
17420     setY : function(y, a, d, c, e){
17421         this.setXY([this.getX(), y], a, d, c, e);
17422     },
17423
17424     // overridden Element method
17425     setSize : function(w, h, a, d, c, e){
17426         this.beforeAction();
17427         var cb = this.createCB(c);
17428         supr.setSize.call(this, w, h, a, d, cb, e);
17429         if(!a){
17430             cb();
17431         }
17432     },
17433
17434     // overridden Element method
17435     setWidth : function(w, a, d, c, e){
17436         this.beforeAction();
17437         var cb = this.createCB(c);
17438         supr.setWidth.call(this, w, a, d, cb, e);
17439         if(!a){
17440             cb();
17441         }
17442     },
17443
17444     // overridden Element method
17445     setHeight : function(h, a, d, c, e){
17446         this.beforeAction();
17447         var cb = this.createCB(c);
17448         supr.setHeight.call(this, h, a, d, cb, e);
17449         if(!a){
17450             cb();
17451         }
17452     },
17453
17454     // overridden Element method
17455     setBounds : function(x, y, w, h, a, d, c, e){
17456         this.beforeAction();
17457         var cb = this.createCB(c);
17458         if(!a){
17459             this.storeXY([x, y]);
17460             supr.setXY.call(this, [x, y]);
17461             supr.setSize.call(this, w, h, a, d, cb, e);
17462             cb();
17463         }else{
17464             supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
17465         }
17466         return this;
17467     },
17468     
17469     /**
17470      * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
17471      * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
17472      * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
17473      * @param {Number} zindex The new z-index to set
17474      * @return {this} The Layer
17475      */
17476     setZIndex : function(zindex){
17477         this.zindex = zindex;
17478         this.setStyle("z-index", zindex + 2);
17479         if(this.shadow){
17480             this.shadow.setZIndex(zindex + 1);
17481         }
17482         if(this.shim){
17483             this.shim.setStyle("z-index", zindex);
17484         }
17485     }
17486 });
17487 })();/*
17488  * Original code for Roojs - LGPL
17489  * <script type="text/javascript">
17490  */
17491  
17492 /**
17493  * @class Roo.XComponent
17494  * A delayed Element creator...
17495  * Or a way to group chunks of interface together.
17496  * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
17497  *  used in conjunction with XComponent.build() it will create an instance of each element,
17498  *  then call addxtype() to build the User interface.
17499  * 
17500  * Mypart.xyx = new Roo.XComponent({
17501
17502     parent : 'Mypart.xyz', // empty == document.element.!!
17503     order : '001',
17504     name : 'xxxx'
17505     region : 'xxxx'
17506     disabled : function() {} 
17507      
17508     tree : function() { // return an tree of xtype declared components
17509         var MODULE = this;
17510         return 
17511         {
17512             xtype : 'NestedLayoutPanel',
17513             // technicall
17514         }
17515      ]
17516  *})
17517  *
17518  *
17519  * It can be used to build a big heiracy, with parent etc.
17520  * or you can just use this to render a single compoent to a dom element
17521  * MYPART.render(Roo.Element | String(id) | dom_element )
17522  *
17523  *
17524  * Usage patterns.
17525  *
17526  * Classic Roo
17527  *
17528  * Roo is designed primarily as a single page application, so the UI build for a standard interface will
17529  * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
17530  *
17531  * Each sub module is expected to have a parent pointing to the class name of it's parent module.
17532  *
17533  * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
17534  * - if mulitple topModules exist, the last one is defined as the top module.
17535  *
17536  * Embeded Roo
17537  * 
17538  * When the top level or multiple modules are to embedded into a existing HTML page,
17539  * the parent element can container '#id' of the element where the module will be drawn.
17540  *
17541  * Bootstrap Roo
17542  *
17543  * Unlike classic Roo, the bootstrap tends not to be used as a single page.
17544  * it relies more on a include mechanism, where sub modules are included into an outer page.
17545  * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
17546  * 
17547  * Bootstrap Roo Included elements
17548  *
17549  * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
17550  * hence confusing the component builder as it thinks there are multiple top level elements. 
17551  *
17552  * String Over-ride & Translations
17553  *
17554  * Our builder application writes all the strings as _strings and _named_strings. This is to enable the translation of elements,
17555  * and also the 'overlaying of string values - needed when different versions of the same application with different text content
17556  * are needed. @see Roo.XComponent.overlayString  
17557  * 
17558  * 
17559  * 
17560  * @extends Roo.util.Observable
17561  * @constructor
17562  * @param cfg {Object} configuration of component
17563  * 
17564  */
17565 Roo.XComponent = function(cfg) {
17566     Roo.apply(this, cfg);
17567     this.addEvents({ 
17568         /**
17569              * @event built
17570              * Fires when this the componnt is built
17571              * @param {Roo.XComponent} c the component
17572              */
17573         'built' : true
17574         
17575     });
17576     this.region = this.region || 'center'; // default..
17577     Roo.XComponent.register(this);
17578     this.modules = false;
17579     this.el = false; // where the layout goes..
17580     
17581     
17582 }
17583 Roo.extend(Roo.XComponent, Roo.util.Observable, {
17584     /**
17585      * @property el
17586      * The created element (with Roo.factory())
17587      * @type {Roo.Layout}
17588      */
17589     el  : false,
17590     
17591     /**
17592      * @property el
17593      * for BC  - use el in new code
17594      * @type {Roo.Layout}
17595      */
17596     panel : false,
17597     
17598     /**
17599      * @property layout
17600      * for BC  - use el in new code
17601      * @type {Roo.Layout}
17602      */
17603     layout : false,
17604     
17605      /**
17606      * @cfg {Function|boolean} disabled
17607      * If this module is disabled by some rule, return true from the funtion
17608      */
17609     disabled : false,
17610     
17611     /**
17612      * @cfg {String} parent 
17613      * Name of parent element which it get xtype added to..
17614      */
17615     parent: false,
17616     
17617     /**
17618      * @cfg {String} order
17619      * Used to set the order in which elements are created (usefull for multiple tabs)
17620      */
17621     
17622     order : false,
17623     /**
17624      * @cfg {String} name
17625      * String to display while loading.
17626      */
17627     name : false,
17628     /**
17629      * @cfg {String} region
17630      * Region to render component to (defaults to center)
17631      */
17632     region : 'center',
17633     
17634     /**
17635      * @cfg {Array} items
17636      * A single item array - the first element is the root of the tree..
17637      * It's done this way to stay compatible with the Xtype system...
17638      */
17639     items : false,
17640     
17641     /**
17642      * @property _tree
17643      * The method that retuns the tree of parts that make up this compoennt 
17644      * @type {function}
17645      */
17646     _tree  : false,
17647     
17648      /**
17649      * render
17650      * render element to dom or tree
17651      * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
17652      */
17653     
17654     render : function(el)
17655     {
17656         
17657         el = el || false;
17658         var hp = this.parent ? 1 : 0;
17659         Roo.debug &&  Roo.log(this);
17660         
17661         var tree = this._tree ? this._tree() : this.tree();
17662
17663         
17664         if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
17665             // if parent is a '#.....' string, then let's use that..
17666             var ename = this.parent.substr(1);
17667             this.parent = false;
17668             Roo.debug && Roo.log(ename);
17669             switch (ename) {
17670                 case 'bootstrap-body':
17671                     if (typeof(tree.el) != 'undefined' && tree.el == document.body)  {
17672                         // this is the BorderLayout standard?
17673                        this.parent = { el : true };
17674                        break;
17675                     }
17676                     if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype)  > -1)  {
17677                         // need to insert stuff...
17678                         this.parent =  {
17679                              el : new Roo.bootstrap.layout.Border({
17680                                  el : document.body, 
17681                      
17682                                  center: {
17683                                     titlebar: false,
17684                                     autoScroll:false,
17685                                     closeOnTab: true,
17686                                     tabPosition: 'top',
17687                                       //resizeTabs: true,
17688                                     alwaysShowTabs: true,
17689                                     hideTabs: false
17690                                      //minTabWidth: 140
17691                                  }
17692                              })
17693                         
17694                          };
17695                          break;
17696                     }
17697                          
17698                     if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
17699                         this.parent = { el :  new  Roo.bootstrap.Body() };
17700                         Roo.debug && Roo.log("setting el to doc body");
17701                          
17702                     } else {
17703                         throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
17704                     }
17705                     break;
17706                 case 'bootstrap':
17707                     this.parent = { el : true};
17708                     // fall through
17709                 default:
17710                     el = Roo.get(ename);
17711                     if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
17712                         this.parent = { el : true};
17713                     }
17714                     
17715                     break;
17716             }
17717                 
17718             
17719             if (!el && !this.parent) {
17720                 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
17721                 return;
17722             }
17723         }
17724         
17725         Roo.debug && Roo.log("EL:");
17726         Roo.debug && Roo.log(el);
17727         Roo.debug && Roo.log("this.parent.el:");
17728         Roo.debug && Roo.log(this.parent.el);
17729         
17730
17731         // altertive root elements ??? - we need a better way to indicate these.
17732         var is_alt = Roo.XComponent.is_alt ||
17733                     (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
17734                     (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
17735                     (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
17736         
17737         
17738         
17739         if (!this.parent && is_alt) {
17740             //el = Roo.get(document.body);
17741             this.parent = { el : true };
17742         }
17743             
17744             
17745         
17746         if (!this.parent) {
17747             
17748             Roo.debug && Roo.log("no parent - creating one");
17749             
17750             el = el ? Roo.get(el) : false;      
17751             
17752             if (typeof(Roo.BorderLayout) == 'undefined' ) {
17753                 
17754                 this.parent =  {
17755                     el : new Roo.bootstrap.layout.Border({
17756                         el: el || document.body,
17757                     
17758                         center: {
17759                             titlebar: false,
17760                             autoScroll:false,
17761                             closeOnTab: true,
17762                             tabPosition: 'top',
17763                              //resizeTabs: true,
17764                             alwaysShowTabs: false,
17765                             hideTabs: true,
17766                             minTabWidth: 140,
17767                             overflow: 'visible'
17768                          }
17769                      })
17770                 };
17771             } else {
17772             
17773                 // it's a top level one..
17774                 this.parent =  {
17775                     el : new Roo.BorderLayout(el || document.body, {
17776                         center: {
17777                             titlebar: false,
17778                             autoScroll:false,
17779                             closeOnTab: true,
17780                             tabPosition: 'top',
17781                              //resizeTabs: true,
17782                             alwaysShowTabs: el && hp? false :  true,
17783                             hideTabs: el || !hp ? true :  false,
17784                             minTabWidth: 140
17785                          }
17786                     })
17787                 };
17788             }
17789         }
17790         
17791         if (!this.parent.el) {
17792                 // probably an old style ctor, which has been disabled.
17793                 return;
17794
17795         }
17796                 // The 'tree' method is  '_tree now' 
17797             
17798         tree.region = tree.region || this.region;
17799         var is_body = false;
17800         if (this.parent.el === true) {
17801             // bootstrap... - body..
17802             if (el) {
17803                 tree.el = el;
17804             }
17805             this.parent.el = Roo.factory(tree);
17806             is_body = true;
17807         }
17808         
17809         this.el = this.parent.el.addxtype(tree, undefined, is_body);
17810         this.fireEvent('built', this);
17811         
17812         this.panel = this.el;
17813         this.layout = this.panel.layout;
17814         this.parentLayout = this.parent.layout  || false;  
17815          
17816     }
17817     
17818 });
17819
17820 Roo.apply(Roo.XComponent, {
17821     /**
17822      * @property  hideProgress
17823      * true to disable the building progress bar.. usefull on single page renders.
17824      * @type Boolean
17825      */
17826     hideProgress : false,
17827     /**
17828      * @property  buildCompleted
17829      * True when the builder has completed building the interface.
17830      * @type Boolean
17831      */
17832     buildCompleted : false,
17833      
17834     /**
17835      * @property  topModule
17836      * the upper most module - uses document.element as it's constructor.
17837      * @type Object
17838      */
17839      
17840     topModule  : false,
17841       
17842     /**
17843      * @property  modules
17844      * array of modules to be created by registration system.
17845      * @type {Array} of Roo.XComponent
17846      */
17847     
17848     modules : [],
17849     /**
17850      * @property  elmodules
17851      * array of modules to be created by which use #ID 
17852      * @type {Array} of Roo.XComponent
17853      */
17854      
17855     elmodules : [],
17856
17857      /**
17858      * @property  is_alt
17859      * Is an alternative Root - normally used by bootstrap or other systems,
17860      *    where the top element in the tree can wrap 'body' 
17861      * @type {boolean}  (default false)
17862      */
17863      
17864     is_alt : false,
17865     /**
17866      * @property  build_from_html
17867      * Build elements from html - used by bootstrap HTML stuff 
17868      *    - this is cleared after build is completed
17869      * @type {boolean}    (default false)
17870      */
17871      
17872     build_from_html : false,
17873     /**
17874      * Register components to be built later.
17875      *
17876      * This solves the following issues
17877      * - Building is not done on page load, but after an authentication process has occured.
17878      * - Interface elements are registered on page load
17879      * - Parent Interface elements may not be loaded before child, so this handles that..
17880      * 
17881      *
17882      * example:
17883      * 
17884      * MyApp.register({
17885           order : '000001',
17886           module : 'Pman.Tab.projectMgr',
17887           region : 'center',
17888           parent : 'Pman.layout',
17889           disabled : false,  // or use a function..
17890         })
17891      
17892      * * @param {Object} details about module
17893      */
17894     register : function(obj) {
17895                 
17896         Roo.XComponent.event.fireEvent('register', obj);
17897         switch(typeof(obj.disabled) ) {
17898                 
17899             case 'undefined':
17900                 break;
17901             
17902             case 'function':
17903                 if ( obj.disabled() ) {
17904                         return;
17905                 }
17906                 break;
17907             
17908             default:
17909                 if (obj.disabled || obj.region == '#disabled') {
17910                         return;
17911                 }
17912                 break;
17913         }
17914                 
17915         this.modules.push(obj);
17916          
17917     },
17918     /**
17919      * convert a string to an object..
17920      * eg. 'AAA.BBB' -> finds AAA.BBB
17921
17922      */
17923     
17924     toObject : function(str)
17925     {
17926         if (!str || typeof(str) == 'object') {
17927             return str;
17928         }
17929         if (str.substring(0,1) == '#') {
17930             return str;
17931         }
17932
17933         var ar = str.split('.');
17934         var rt, o;
17935         rt = ar.shift();
17936             /** eval:var:o */
17937         try {
17938             eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
17939         } catch (e) {
17940             throw "Module not found : " + str;
17941         }
17942         
17943         if (o === false) {
17944             throw "Module not found : " + str;
17945         }
17946         Roo.each(ar, function(e) {
17947             if (typeof(o[e]) == 'undefined') {
17948                 throw "Module not found : " + str;
17949             }
17950             o = o[e];
17951         });
17952         
17953         return o;
17954         
17955     },
17956     
17957     
17958     /**
17959      * move modules into their correct place in the tree..
17960      * 
17961      */
17962     preBuild : function ()
17963     {
17964         var _t = this;
17965         Roo.each(this.modules , function (obj)
17966         {
17967             Roo.XComponent.event.fireEvent('beforebuild', obj);
17968             
17969             var opar = obj.parent;
17970             try { 
17971                 obj.parent = this.toObject(opar);
17972             } catch(e) {
17973                 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
17974                 return;
17975             }
17976             
17977             if (!obj.parent) {
17978                 Roo.debug && Roo.log("GOT top level module");
17979                 Roo.debug && Roo.log(obj);
17980                 obj.modules = new Roo.util.MixedCollection(false, 
17981                     function(o) { return o.order + '' }
17982                 );
17983                 this.topModule = obj;
17984                 return;
17985             }
17986                         // parent is a string (usually a dom element name..)
17987             if (typeof(obj.parent) == 'string') {
17988                 this.elmodules.push(obj);
17989                 return;
17990             }
17991             if (obj.parent.constructor != Roo.XComponent) {
17992                 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
17993             }
17994             if (!obj.parent.modules) {
17995                 obj.parent.modules = new Roo.util.MixedCollection(false, 
17996                     function(o) { return o.order + '' }
17997                 );
17998             }
17999             if (obj.parent.disabled) {
18000                 obj.disabled = true;
18001             }
18002             obj.parent.modules.add(obj);
18003         }, this);
18004     },
18005     
18006      /**
18007      * make a list of modules to build.
18008      * @return {Array} list of modules. 
18009      */ 
18010     
18011     buildOrder : function()
18012     {
18013         var _this = this;
18014         var cmp = function(a,b) {   
18015             return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
18016         };
18017         if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
18018             throw "No top level modules to build";
18019         }
18020         
18021         // make a flat list in order of modules to build.
18022         var mods = this.topModule ? [ this.topModule ] : [];
18023                 
18024         
18025         // elmodules (is a list of DOM based modules )
18026         Roo.each(this.elmodules, function(e) {
18027             mods.push(e);
18028             if (!this.topModule &&
18029                 typeof(e.parent) == 'string' &&
18030                 e.parent.substring(0,1) == '#' &&
18031                 Roo.get(e.parent.substr(1))
18032                ) {
18033                 
18034                 _this.topModule = e;
18035             }
18036             
18037         });
18038
18039         
18040         // add modules to their parents..
18041         var addMod = function(m) {
18042             Roo.debug && Roo.log("build Order: add: " + m.name);
18043                 
18044             mods.push(m);
18045             if (m.modules && !m.disabled) {
18046                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
18047                 m.modules.keySort('ASC',  cmp );
18048                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
18049     
18050                 m.modules.each(addMod);
18051             } else {
18052                 Roo.debug && Roo.log("build Order: no child modules");
18053             }
18054             // not sure if this is used any more..
18055             if (m.finalize) {
18056                 m.finalize.name = m.name + " (clean up) ";
18057                 mods.push(m.finalize);
18058             }
18059             
18060         }
18061         if (this.topModule && this.topModule.modules) { 
18062             this.topModule.modules.keySort('ASC',  cmp );
18063             this.topModule.modules.each(addMod);
18064         } 
18065         return mods;
18066     },
18067     
18068      /**
18069      * Build the registered modules.
18070      * @param {Object} parent element.
18071      * @param {Function} optional method to call after module has been added.
18072      * 
18073      */ 
18074    
18075     build : function(opts) 
18076     {
18077         
18078         if (typeof(opts) != 'undefined') {
18079             Roo.apply(this,opts);
18080         }
18081         
18082         this.preBuild();
18083         var mods = this.buildOrder();
18084       
18085         //this.allmods = mods;
18086         //Roo.debug && Roo.log(mods);
18087         //return;
18088         if (!mods.length) { // should not happen
18089             throw "NO modules!!!";
18090         }
18091         
18092         
18093         var msg = "Building Interface...";
18094         // flash it up as modal - so we store the mask!?
18095         if (!this.hideProgress && Roo.MessageBox) {
18096             Roo.MessageBox.show({ title: 'loading' });
18097             Roo.MessageBox.show({
18098                title: "Please wait...",
18099                msg: msg,
18100                width:450,
18101                progress:true,
18102                buttons : false,
18103                closable:false,
18104                modal: false
18105               
18106             });
18107         }
18108         var total = mods.length;
18109         
18110         var _this = this;
18111         var progressRun = function() {
18112             if (!mods.length) {
18113                 Roo.debug && Roo.log('hide?');
18114                 if (!this.hideProgress && Roo.MessageBox) {
18115                     Roo.MessageBox.hide();
18116                 }
18117                 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
18118                 
18119                 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
18120                 
18121                 // THE END...
18122                 return false;   
18123             }
18124             
18125             var m = mods.shift();
18126             
18127             
18128             Roo.debug && Roo.log(m);
18129             // not sure if this is supported any more.. - modules that are are just function
18130             if (typeof(m) == 'function') { 
18131                 m.call(this);
18132                 return progressRun.defer(10, _this);
18133             } 
18134             
18135             
18136             msg = "Building Interface " + (total  - mods.length) + 
18137                     " of " + total + 
18138                     (m.name ? (' - ' + m.name) : '');
18139                         Roo.debug && Roo.log(msg);
18140             if (!_this.hideProgress &&  Roo.MessageBox) { 
18141                 Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
18142             }
18143             
18144          
18145             // is the module disabled?
18146             var disabled = (typeof(m.disabled) == 'function') ?
18147                 m.disabled.call(m.module.disabled) : m.disabled;    
18148             
18149             
18150             if (disabled) {
18151                 return progressRun(); // we do not update the display!
18152             }
18153             
18154             // now build 
18155             
18156                         
18157                         
18158             m.render();
18159             // it's 10 on top level, and 1 on others??? why...
18160             return progressRun.defer(10, _this);
18161              
18162         }
18163         progressRun.defer(1, _this);
18164      
18165         
18166         
18167     },
18168     /**
18169      * Overlay a set of modified strings onto a component
18170      * This is dependant on our builder exporting the strings and 'named strings' elements.
18171      * 
18172      * @param {Object} element to overlay on - eg. Pman.Dialog.Login
18173      * @param {Object} associative array of 'named' string and it's new value.
18174      * 
18175      */
18176         overlayStrings : function( component, strings )
18177     {
18178         if (typeof(component['_named_strings']) == 'undefined') {
18179             throw "ERROR: component does not have _named_strings";
18180         }
18181         for ( var k in strings ) {
18182             var md = typeof(component['_named_strings'][k]) == 'undefined' ? false : component['_named_strings'][k];
18183             if (md !== false) {
18184                 component['_strings'][md] = strings[k];
18185             } else {
18186                 Roo.log('could not find named string: ' + k + ' in');
18187                 Roo.log(component);
18188             }
18189             
18190         }
18191         
18192     },
18193     
18194         
18195         /**
18196          * Event Object.
18197          *
18198          *
18199          */
18200         event: false, 
18201     /**
18202          * wrapper for event.on - aliased later..  
18203          * Typically use to register a event handler for register:
18204          *
18205          * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
18206          *
18207          */
18208     on : false
18209    
18210     
18211     
18212 });
18213
18214 Roo.XComponent.event = new Roo.util.Observable({
18215                 events : { 
18216                         /**
18217                          * @event register
18218                          * Fires when an Component is registered,
18219                          * set the disable property on the Component to stop registration.
18220                          * @param {Roo.XComponent} c the component being registerd.
18221                          * 
18222                          */
18223                         'register' : true,
18224             /**
18225                          * @event beforebuild
18226                          * Fires before each Component is built
18227                          * can be used to apply permissions.
18228                          * @param {Roo.XComponent} c the component being registerd.
18229                          * 
18230                          */
18231                         'beforebuild' : true,
18232                         /**
18233                          * @event buildcomplete
18234                          * Fires on the top level element when all elements have been built
18235                          * @param {Roo.XComponent} the top level component.
18236                          */
18237                         'buildcomplete' : true
18238                         
18239                 }
18240 });
18241
18242 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event); 
18243  //
18244  /**
18245  * marked - a markdown parser
18246  * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
18247  * https://github.com/chjj/marked
18248  */
18249
18250
18251 /**
18252  *
18253  * Roo.Markdown - is a very crude wrapper around marked..
18254  *
18255  * usage:
18256  * 
18257  * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
18258  * 
18259  * Note: move the sample code to the bottom of this
18260  * file before uncommenting it.
18261  *
18262  */
18263
18264 Roo.Markdown = {};
18265 Roo.Markdown.toHtml = function(text) {
18266     
18267     var c = new Roo.Markdown.marked.setOptions({
18268             renderer: new Roo.Markdown.marked.Renderer(),
18269             gfm: true,
18270             tables: true,
18271             breaks: false,
18272             pedantic: false,
18273             sanitize: false,
18274             smartLists: true,
18275             smartypants: false
18276           });
18277     // A FEW HACKS!!?
18278     
18279     text = text.replace(/\\\n/g,' ');
18280     return Roo.Markdown.marked(text);
18281 };
18282 //
18283 // converter
18284 //
18285 // Wraps all "globals" so that the only thing
18286 // exposed is makeHtml().
18287 //
18288 (function() {
18289     
18290      /**
18291          * eval:var:escape
18292          * eval:var:unescape
18293          * eval:var:replace
18294          */
18295       
18296     /**
18297      * Helpers
18298      */
18299     
18300     var escape = function (html, encode) {
18301       return html
18302         .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&amp;')
18303         .replace(/</g, '&lt;')
18304         .replace(/>/g, '&gt;')
18305         .replace(/"/g, '&quot;')
18306         .replace(/'/g, '&#39;');
18307     }
18308     
18309     var unescape = function (html) {
18310         // explicitly match decimal, hex, and named HTML entities 
18311       return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
18312         n = n.toLowerCase();
18313         if (n === 'colon') { return ':'; }
18314         if (n.charAt(0) === '#') {
18315           return n.charAt(1) === 'x'
18316             ? String.fromCharCode(parseInt(n.substring(2), 16))
18317             : String.fromCharCode(+n.substring(1));
18318         }
18319         return '';
18320       });
18321     }
18322     
18323     var replace = function (regex, opt) {
18324       regex = regex.source;
18325       opt = opt || '';
18326       return function self(name, val) {
18327         if (!name) { return new RegExp(regex, opt); }
18328         val = val.source || val;
18329         val = val.replace(/(^|[^\[])\^/g, '$1');
18330         regex = regex.replace(name, val);
18331         return self;
18332       };
18333     }
18334
18335
18336          /**
18337          * eval:var:noop
18338     */
18339     var noop = function () {}
18340     noop.exec = noop;
18341     
18342          /**
18343          * eval:var:merge
18344     */
18345     var merge = function (obj) {
18346       var i = 1
18347         , target
18348         , key;
18349     
18350       for (; i < arguments.length; i++) {
18351         target = arguments[i];
18352         for (key in target) {
18353           if (Object.prototype.hasOwnProperty.call(target, key)) {
18354             obj[key] = target[key];
18355           }
18356         }
18357       }
18358     
18359       return obj;
18360     }
18361     
18362     
18363     /**
18364      * Block-Level Grammar
18365      */
18366     
18367     
18368     
18369     
18370     var block = {
18371       newline: /^\n+/,
18372       code: /^( {4}[^\n]+\n*)+/,
18373       fences: noop,
18374       hr: /^( *[-*_]){3,} *(?:\n+|$)/,
18375       heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
18376       nptable: noop,
18377       lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
18378       blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
18379       list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
18380       html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
18381       def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
18382       table: noop,
18383       paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
18384       text: /^[^\n]+/
18385     };
18386     
18387     block.bullet = /(?:[*+-]|\d+\.)/;
18388     block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
18389     block.item = replace(block.item, 'gm')
18390       (/bull/g, block.bullet)
18391       ();
18392     
18393     block.list = replace(block.list)
18394       (/bull/g, block.bullet)
18395       ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
18396       ('def', '\\n+(?=' + block.def.source + ')')
18397       ();
18398     
18399     block.blockquote = replace(block.blockquote)
18400       ('def', block.def)
18401       ();
18402     
18403     block._tag = '(?!(?:'
18404       + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
18405       + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
18406       + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
18407     
18408     block.html = replace(block.html)
18409       ('comment', /<!--[\s\S]*?-->/)
18410       ('closed', /<(tag)[\s\S]+?<\/\1>/)
18411       ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
18412       (/tag/g, block._tag)
18413       ();
18414     
18415     block.paragraph = replace(block.paragraph)
18416       ('hr', block.hr)
18417       ('heading', block.heading)
18418       ('lheading', block.lheading)
18419       ('blockquote', block.blockquote)
18420       ('tag', '<' + block._tag)
18421       ('def', block.def)
18422       ();
18423     
18424     /**
18425      * Normal Block Grammar
18426      */
18427     
18428     block.normal = merge({}, block);
18429     
18430     /**
18431      * GFM Block Grammar
18432      */
18433     
18434     block.gfm = merge({}, block.normal, {
18435       fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
18436       paragraph: /^/,
18437       heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
18438     });
18439     
18440     block.gfm.paragraph = replace(block.paragraph)
18441       ('(?!', '(?!'
18442         + block.gfm.fences.source.replace('\\1', '\\2') + '|'
18443         + block.list.source.replace('\\1', '\\3') + '|')
18444       ();
18445     
18446     /**
18447      * GFM + Tables Block Grammar
18448      */
18449     
18450     block.tables = merge({}, block.gfm, {
18451       nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
18452       table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
18453     });
18454     
18455     /**
18456      * Block Lexer
18457      */
18458     
18459     var Lexer = function (options) {
18460       this.tokens = [];
18461       this.tokens.links = {};
18462       this.options = options || marked.defaults;
18463       this.rules = block.normal;
18464     
18465       if (this.options.gfm) {
18466         if (this.options.tables) {
18467           this.rules = block.tables;
18468         } else {
18469           this.rules = block.gfm;
18470         }
18471       }
18472     }
18473     
18474     /**
18475      * Expose Block Rules
18476      */
18477     
18478     Lexer.rules = block;
18479     
18480     /**
18481      * Static Lex Method
18482      */
18483     
18484     Lexer.lex = function(src, options) {
18485       var lexer = new Lexer(options);
18486       return lexer.lex(src);
18487     };
18488     
18489     /**
18490      * Preprocessing
18491      */
18492     
18493     Lexer.prototype.lex = function(src) {
18494       src = src
18495         .replace(/\r\n|\r/g, '\n')
18496         .replace(/\t/g, '    ')
18497         .replace(/\u00a0/g, ' ')
18498         .replace(/\u2424/g, '\n');
18499     
18500       return this.token(src, true);
18501     };
18502     
18503     /**
18504      * Lexing
18505      */
18506     
18507     Lexer.prototype.token = function(src, top, bq) {
18508       var src = src.replace(/^ +$/gm, '')
18509         , next
18510         , loose
18511         , cap
18512         , bull
18513         , b
18514         , item
18515         , space
18516         , i
18517         , l;
18518     
18519       while (src) {
18520         // newline
18521         if (cap = this.rules.newline.exec(src)) {
18522           src = src.substring(cap[0].length);
18523           if (cap[0].length > 1) {
18524             this.tokens.push({
18525               type: 'space'
18526             });
18527           }
18528         }
18529     
18530         // code
18531         if (cap = this.rules.code.exec(src)) {
18532           src = src.substring(cap[0].length);
18533           cap = cap[0].replace(/^ {4}/gm, '');
18534           this.tokens.push({
18535             type: 'code',
18536             text: !this.options.pedantic
18537               ? cap.replace(/\n+$/, '')
18538               : cap
18539           });
18540           continue;
18541         }
18542     
18543         // fences (gfm)
18544         if (cap = this.rules.fences.exec(src)) {
18545           src = src.substring(cap[0].length);
18546           this.tokens.push({
18547             type: 'code',
18548             lang: cap[2],
18549             text: cap[3] || ''
18550           });
18551           continue;
18552         }
18553     
18554         // heading
18555         if (cap = this.rules.heading.exec(src)) {
18556           src = src.substring(cap[0].length);
18557           this.tokens.push({
18558             type: 'heading',
18559             depth: cap[1].length,
18560             text: cap[2]
18561           });
18562           continue;
18563         }
18564     
18565         // table no leading pipe (gfm)
18566         if (top && (cap = this.rules.nptable.exec(src))) {
18567           src = src.substring(cap[0].length);
18568     
18569           item = {
18570             type: 'table',
18571             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
18572             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
18573             cells: cap[3].replace(/\n$/, '').split('\n')
18574           };
18575     
18576           for (i = 0; i < item.align.length; i++) {
18577             if (/^ *-+: *$/.test(item.align[i])) {
18578               item.align[i] = 'right';
18579             } else if (/^ *:-+: *$/.test(item.align[i])) {
18580               item.align[i] = 'center';
18581             } else if (/^ *:-+ *$/.test(item.align[i])) {
18582               item.align[i] = 'left';
18583             } else {
18584               item.align[i] = null;
18585             }
18586           }
18587     
18588           for (i = 0; i < item.cells.length; i++) {
18589             item.cells[i] = item.cells[i].split(/ *\| */);
18590           }
18591     
18592           this.tokens.push(item);
18593     
18594           continue;
18595         }
18596     
18597         // lheading
18598         if (cap = this.rules.lheading.exec(src)) {
18599           src = src.substring(cap[0].length);
18600           this.tokens.push({
18601             type: 'heading',
18602             depth: cap[2] === '=' ? 1 : 2,
18603             text: cap[1]
18604           });
18605           continue;
18606         }
18607     
18608         // hr
18609         if (cap = this.rules.hr.exec(src)) {
18610           src = src.substring(cap[0].length);
18611           this.tokens.push({
18612             type: 'hr'
18613           });
18614           continue;
18615         }
18616     
18617         // blockquote
18618         if (cap = this.rules.blockquote.exec(src)) {
18619           src = src.substring(cap[0].length);
18620     
18621           this.tokens.push({
18622             type: 'blockquote_start'
18623           });
18624     
18625           cap = cap[0].replace(/^ *> ?/gm, '');
18626     
18627           // Pass `top` to keep the current
18628           // "toplevel" state. This is exactly
18629           // how markdown.pl works.
18630           this.token(cap, top, true);
18631     
18632           this.tokens.push({
18633             type: 'blockquote_end'
18634           });
18635     
18636           continue;
18637         }
18638     
18639         // list
18640         if (cap = this.rules.list.exec(src)) {
18641           src = src.substring(cap[0].length);
18642           bull = cap[2];
18643     
18644           this.tokens.push({
18645             type: 'list_start',
18646             ordered: bull.length > 1
18647           });
18648     
18649           // Get each top-level item.
18650           cap = cap[0].match(this.rules.item);
18651     
18652           next = false;
18653           l = cap.length;
18654           i = 0;
18655     
18656           for (; i < l; i++) {
18657             item = cap[i];
18658     
18659             // Remove the list item's bullet
18660             // so it is seen as the next token.
18661             space = item.length;
18662             item = item.replace(/^ *([*+-]|\d+\.) +/, '');
18663     
18664             // Outdent whatever the
18665             // list item contains. Hacky.
18666             if (~item.indexOf('\n ')) {
18667               space -= item.length;
18668               item = !this.options.pedantic
18669                 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
18670                 : item.replace(/^ {1,4}/gm, '');
18671             }
18672     
18673             // Determine whether the next list item belongs here.
18674             // Backpedal if it does not belong in this list.
18675             if (this.options.smartLists && i !== l - 1) {
18676               b = block.bullet.exec(cap[i + 1])[0];
18677               if (bull !== b && !(bull.length > 1 && b.length > 1)) {
18678                 src = cap.slice(i + 1).join('\n') + src;
18679                 i = l - 1;
18680               }
18681             }
18682     
18683             // Determine whether item is loose or not.
18684             // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
18685             // for discount behavior.
18686             loose = next || /\n\n(?!\s*$)/.test(item);
18687             if (i !== l - 1) {
18688               next = item.charAt(item.length - 1) === '\n';
18689               if (!loose) { loose = next; }
18690             }
18691     
18692             this.tokens.push({
18693               type: loose
18694                 ? 'loose_item_start'
18695                 : 'list_item_start'
18696             });
18697     
18698             // Recurse.
18699             this.token(item, false, bq);
18700     
18701             this.tokens.push({
18702               type: 'list_item_end'
18703             });
18704           }
18705     
18706           this.tokens.push({
18707             type: 'list_end'
18708           });
18709     
18710           continue;
18711         }
18712     
18713         // html
18714         if (cap = this.rules.html.exec(src)) {
18715           src = src.substring(cap[0].length);
18716           this.tokens.push({
18717             type: this.options.sanitize
18718               ? 'paragraph'
18719               : 'html',
18720             pre: !this.options.sanitizer
18721               && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
18722             text: cap[0]
18723           });
18724           continue;
18725         }
18726     
18727         // def
18728         if ((!bq && top) && (cap = this.rules.def.exec(src))) {
18729           src = src.substring(cap[0].length);
18730           this.tokens.links[cap[1].toLowerCase()] = {
18731             href: cap[2],
18732             title: cap[3]
18733           };
18734           continue;
18735         }
18736     
18737         // table (gfm)
18738         if (top && (cap = this.rules.table.exec(src))) {
18739           src = src.substring(cap[0].length);
18740     
18741           item = {
18742             type: 'table',
18743             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
18744             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
18745             cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
18746           };
18747     
18748           for (i = 0; i < item.align.length; i++) {
18749             if (/^ *-+: *$/.test(item.align[i])) {
18750               item.align[i] = 'right';
18751             } else if (/^ *:-+: *$/.test(item.align[i])) {
18752               item.align[i] = 'center';
18753             } else if (/^ *:-+ *$/.test(item.align[i])) {
18754               item.align[i] = 'left';
18755             } else {
18756               item.align[i] = null;
18757             }
18758           }
18759     
18760           for (i = 0; i < item.cells.length; i++) {
18761             item.cells[i] = item.cells[i]
18762               .replace(/^ *\| *| *\| *$/g, '')
18763               .split(/ *\| */);
18764           }
18765     
18766           this.tokens.push(item);
18767     
18768           continue;
18769         }
18770     
18771         // top-level paragraph
18772         if (top && (cap = this.rules.paragraph.exec(src))) {
18773           src = src.substring(cap[0].length);
18774           this.tokens.push({
18775             type: 'paragraph',
18776             text: cap[1].charAt(cap[1].length - 1) === '\n'
18777               ? cap[1].slice(0, -1)
18778               : cap[1]
18779           });
18780           continue;
18781         }
18782     
18783         // text
18784         if (cap = this.rules.text.exec(src)) {
18785           // Top-level should never reach here.
18786           src = src.substring(cap[0].length);
18787           this.tokens.push({
18788             type: 'text',
18789             text: cap[0]
18790           });
18791           continue;
18792         }
18793     
18794         if (src) {
18795           throw new
18796             Error('Infinite loop on byte: ' + src.charCodeAt(0));
18797         }
18798       }
18799     
18800       return this.tokens;
18801     };
18802     
18803     /**
18804      * Inline-Level Grammar
18805      */
18806     
18807     var inline = {
18808       escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
18809       autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
18810       url: noop,
18811       tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
18812       link: /^!?\[(inside)\]\(href\)/,
18813       reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
18814       nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
18815       strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
18816       em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
18817       code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
18818       br: /^ {2,}\n(?!\s*$)/,
18819       del: noop,
18820       text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
18821     };
18822     
18823     inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
18824     inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
18825     
18826     inline.link = replace(inline.link)
18827       ('inside', inline._inside)
18828       ('href', inline._href)
18829       ();
18830     
18831     inline.reflink = replace(inline.reflink)
18832       ('inside', inline._inside)
18833       ();
18834     
18835     /**
18836      * Normal Inline Grammar
18837      */
18838     
18839     inline.normal = merge({}, inline);
18840     
18841     /**
18842      * Pedantic Inline Grammar
18843      */
18844     
18845     inline.pedantic = merge({}, inline.normal, {
18846       strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
18847       em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
18848     });
18849     
18850     /**
18851      * GFM Inline Grammar
18852      */
18853     
18854     inline.gfm = merge({}, inline.normal, {
18855       escape: replace(inline.escape)('])', '~|])')(),
18856       url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
18857       del: /^~~(?=\S)([\s\S]*?\S)~~/,
18858       text: replace(inline.text)
18859         (']|', '~]|')
18860         ('|', '|https?://|')
18861         ()
18862     });
18863     
18864     /**
18865      * GFM + Line Breaks Inline Grammar
18866      */
18867     
18868     inline.breaks = merge({}, inline.gfm, {
18869       br: replace(inline.br)('{2,}', '*')(),
18870       text: replace(inline.gfm.text)('{2,}', '*')()
18871     });
18872     
18873     /**
18874      * Inline Lexer & Compiler
18875      */
18876     
18877     var InlineLexer  = function (links, options) {
18878       this.options = options || marked.defaults;
18879       this.links = links;
18880       this.rules = inline.normal;
18881       this.renderer = this.options.renderer || new Renderer;
18882       this.renderer.options = this.options;
18883     
18884       if (!this.links) {
18885         throw new
18886           Error('Tokens array requires a `links` property.');
18887       }
18888     
18889       if (this.options.gfm) {
18890         if (this.options.breaks) {
18891           this.rules = inline.breaks;
18892         } else {
18893           this.rules = inline.gfm;
18894         }
18895       } else if (this.options.pedantic) {
18896         this.rules = inline.pedantic;
18897       }
18898     }
18899     
18900     /**
18901      * Expose Inline Rules
18902      */
18903     
18904     InlineLexer.rules = inline;
18905     
18906     /**
18907      * Static Lexing/Compiling Method
18908      */
18909     
18910     InlineLexer.output = function(src, links, options) {
18911       var inline = new InlineLexer(links, options);
18912       return inline.output(src);
18913     };
18914     
18915     /**
18916      * Lexing/Compiling
18917      */
18918     
18919     InlineLexer.prototype.output = function(src) {
18920       var out = ''
18921         , link
18922         , text
18923         , href
18924         , cap;
18925     
18926       while (src) {
18927         // escape
18928         if (cap = this.rules.escape.exec(src)) {
18929           src = src.substring(cap[0].length);
18930           out += cap[1];
18931           continue;
18932         }
18933     
18934         // autolink
18935         if (cap = this.rules.autolink.exec(src)) {
18936           src = src.substring(cap[0].length);
18937           if (cap[2] === '@') {
18938             text = cap[1].charAt(6) === ':'
18939               ? this.mangle(cap[1].substring(7))
18940               : this.mangle(cap[1]);
18941             href = this.mangle('mailto:') + text;
18942           } else {
18943             text = escape(cap[1]);
18944             href = text;
18945           }
18946           out += this.renderer.link(href, null, text);
18947           continue;
18948         }
18949     
18950         // url (gfm)
18951         if (!this.inLink && (cap = this.rules.url.exec(src))) {
18952           src = src.substring(cap[0].length);
18953           text = escape(cap[1]);
18954           href = text;
18955           out += this.renderer.link(href, null, text);
18956           continue;
18957         }
18958     
18959         // tag
18960         if (cap = this.rules.tag.exec(src)) {
18961           if (!this.inLink && /^<a /i.test(cap[0])) {
18962             this.inLink = true;
18963           } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
18964             this.inLink = false;
18965           }
18966           src = src.substring(cap[0].length);
18967           out += this.options.sanitize
18968             ? this.options.sanitizer
18969               ? this.options.sanitizer(cap[0])
18970               : escape(cap[0])
18971             : cap[0];
18972           continue;
18973         }
18974     
18975         // link
18976         if (cap = this.rules.link.exec(src)) {
18977           src = src.substring(cap[0].length);
18978           this.inLink = true;
18979           out += this.outputLink(cap, {
18980             href: cap[2],
18981             title: cap[3]
18982           });
18983           this.inLink = false;
18984           continue;
18985         }
18986     
18987         // reflink, nolink
18988         if ((cap = this.rules.reflink.exec(src))
18989             || (cap = this.rules.nolink.exec(src))) {
18990           src = src.substring(cap[0].length);
18991           link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
18992           link = this.links[link.toLowerCase()];
18993           if (!link || !link.href) {
18994             out += cap[0].charAt(0);
18995             src = cap[0].substring(1) + src;
18996             continue;
18997           }
18998           this.inLink = true;
18999           out += this.outputLink(cap, link);
19000           this.inLink = false;
19001           continue;
19002         }
19003     
19004         // strong
19005         if (cap = this.rules.strong.exec(src)) {
19006           src = src.substring(cap[0].length);
19007           out += this.renderer.strong(this.output(cap[2] || cap[1]));
19008           continue;
19009         }
19010     
19011         // em
19012         if (cap = this.rules.em.exec(src)) {
19013           src = src.substring(cap[0].length);
19014           out += this.renderer.em(this.output(cap[2] || cap[1]));
19015           continue;
19016         }
19017     
19018         // code
19019         if (cap = this.rules.code.exec(src)) {
19020           src = src.substring(cap[0].length);
19021           out += this.renderer.codespan(escape(cap[2], true));
19022           continue;
19023         }
19024     
19025         // br
19026         if (cap = this.rules.br.exec(src)) {
19027           src = src.substring(cap[0].length);
19028           out += this.renderer.br();
19029           continue;
19030         }
19031     
19032         // del (gfm)
19033         if (cap = this.rules.del.exec(src)) {
19034           src = src.substring(cap[0].length);
19035           out += this.renderer.del(this.output(cap[1]));
19036           continue;
19037         }
19038     
19039         // text
19040         if (cap = this.rules.text.exec(src)) {
19041           src = src.substring(cap[0].length);
19042           out += this.renderer.text(escape(this.smartypants(cap[0])));
19043           continue;
19044         }
19045     
19046         if (src) {
19047           throw new
19048             Error('Infinite loop on byte: ' + src.charCodeAt(0));
19049         }
19050       }
19051     
19052       return out;
19053     };
19054     
19055     /**
19056      * Compile Link
19057      */
19058     
19059     InlineLexer.prototype.outputLink = function(cap, link) {
19060       var href = escape(link.href)
19061         , title = link.title ? escape(link.title) : null;
19062     
19063       return cap[0].charAt(0) !== '!'
19064         ? this.renderer.link(href, title, this.output(cap[1]))
19065         : this.renderer.image(href, title, escape(cap[1]));
19066     };
19067     
19068     /**
19069      * Smartypants Transformations
19070      */
19071     
19072     InlineLexer.prototype.smartypants = function(text) {
19073       if (!this.options.smartypants)  { return text; }
19074       return text
19075         // em-dashes
19076         .replace(/---/g, '\u2014')
19077         // en-dashes
19078         .replace(/--/g, '\u2013')
19079         // opening singles
19080         .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
19081         // closing singles & apostrophes
19082         .replace(/'/g, '\u2019')
19083         // opening doubles
19084         .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
19085         // closing doubles
19086         .replace(/"/g, '\u201d')
19087         // ellipses
19088         .replace(/\.{3}/g, '\u2026');
19089     };
19090     
19091     /**
19092      * Mangle Links
19093      */
19094     
19095     InlineLexer.prototype.mangle = function(text) {
19096       if (!this.options.mangle) { return text; }
19097       var out = ''
19098         , l = text.length
19099         , i = 0
19100         , ch;
19101     
19102       for (; i < l; i++) {
19103         ch = text.charCodeAt(i);
19104         if (Math.random() > 0.5) {
19105           ch = 'x' + ch.toString(16);
19106         }
19107         out += '&#' + ch + ';';
19108       }
19109     
19110       return out;
19111     };
19112     
19113     /**
19114      * Renderer
19115      */
19116     
19117      /**
19118          * eval:var:Renderer
19119     */
19120     
19121     var Renderer   = function (options) {
19122       this.options = options || {};
19123     }
19124     
19125     Renderer.prototype.code = function(code, lang, escaped) {
19126       if (this.options.highlight) {
19127         var out = this.options.highlight(code, lang);
19128         if (out != null && out !== code) {
19129           escaped = true;
19130           code = out;
19131         }
19132       } else {
19133             // hack!!! - it's already escapeD?
19134             escaped = true;
19135       }
19136     
19137       if (!lang) {
19138         return '<pre><code>'
19139           + (escaped ? code : escape(code, true))
19140           + '\n</code></pre>';
19141       }
19142     
19143       return '<pre><code class="'
19144         + this.options.langPrefix
19145         + escape(lang, true)
19146         + '">'
19147         + (escaped ? code : escape(code, true))
19148         + '\n</code></pre>\n';
19149     };
19150     
19151     Renderer.prototype.blockquote = function(quote) {
19152       return '<blockquote>\n' + quote + '</blockquote>\n';
19153     };
19154     
19155     Renderer.prototype.html = function(html) {
19156       return html;
19157     };
19158     
19159     Renderer.prototype.heading = function(text, level, raw) {
19160       return '<h'
19161         + level
19162         + ' id="'
19163         + this.options.headerPrefix
19164         + raw.toLowerCase().replace(/[^\w]+/g, '-')
19165         + '">'
19166         + text
19167         + '</h'
19168         + level
19169         + '>\n';
19170     };
19171     
19172     Renderer.prototype.hr = function() {
19173       return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
19174     };
19175     
19176     Renderer.prototype.list = function(body, ordered) {
19177       var type = ordered ? 'ol' : 'ul';
19178       return '<' + type + '>\n' + body + '</' + type + '>\n';
19179     };
19180     
19181     Renderer.prototype.listitem = function(text) {
19182       return '<li>' + text + '</li>\n';
19183     };
19184     
19185     Renderer.prototype.paragraph = function(text) {
19186       return '<p>' + text + '</p>\n';
19187     };
19188     
19189     Renderer.prototype.table = function(header, body) {
19190       return '<table class="table table-striped">\n'
19191         + '<thead>\n'
19192         + header
19193         + '</thead>\n'
19194         + '<tbody>\n'
19195         + body
19196         + '</tbody>\n'
19197         + '</table>\n';
19198     };
19199     
19200     Renderer.prototype.tablerow = function(content) {
19201       return '<tr>\n' + content + '</tr>\n';
19202     };
19203     
19204     Renderer.prototype.tablecell = function(content, flags) {
19205       var type = flags.header ? 'th' : 'td';
19206       var tag = flags.align
19207         ? '<' + type + ' style="text-align:' + flags.align + '">'
19208         : '<' + type + '>';
19209       return tag + content + '</' + type + '>\n';
19210     };
19211     
19212     // span level renderer
19213     Renderer.prototype.strong = function(text) {
19214       return '<strong>' + text + '</strong>';
19215     };
19216     
19217     Renderer.prototype.em = function(text) {
19218       return '<em>' + text + '</em>';
19219     };
19220     
19221     Renderer.prototype.codespan = function(text) {
19222       return '<code>' + text + '</code>';
19223     };
19224     
19225     Renderer.prototype.br = function() {
19226       return this.options.xhtml ? '<br/>' : '<br>';
19227     };
19228     
19229     Renderer.prototype.del = function(text) {
19230       return '<del>' + text + '</del>';
19231     };
19232     
19233     Renderer.prototype.link = function(href, title, text) {
19234       if (this.options.sanitize) {
19235         try {
19236           var prot = decodeURIComponent(unescape(href))
19237             .replace(/[^\w:]/g, '')
19238             .toLowerCase();
19239         } catch (e) {
19240           return '';
19241         }
19242         if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
19243           return '';
19244         }
19245       }
19246       var out = '<a href="' + href + '"';
19247       if (title) {
19248         out += ' title="' + title + '"';
19249       }
19250       out += '>' + text + '</a>';
19251       return out;
19252     };
19253     
19254     Renderer.prototype.image = function(href, title, text) {
19255       var out = '<img src="' + href + '" alt="' + text + '"';
19256       if (title) {
19257         out += ' title="' + title + '"';
19258       }
19259       out += this.options.xhtml ? '/>' : '>';
19260       return out;
19261     };
19262     
19263     Renderer.prototype.text = function(text) {
19264       return text;
19265     };
19266     
19267     /**
19268      * Parsing & Compiling
19269      */
19270          /**
19271          * eval:var:Parser
19272     */
19273     
19274     var Parser= function (options) {
19275       this.tokens = [];
19276       this.token = null;
19277       this.options = options || marked.defaults;
19278       this.options.renderer = this.options.renderer || new Renderer;
19279       this.renderer = this.options.renderer;
19280       this.renderer.options = this.options;
19281     }
19282     
19283     /**
19284      * Static Parse Method
19285      */
19286     
19287     Parser.parse = function(src, options, renderer) {
19288       var parser = new Parser(options, renderer);
19289       return parser.parse(src);
19290     };
19291     
19292     /**
19293      * Parse Loop
19294      */
19295     
19296     Parser.prototype.parse = function(src) {
19297       this.inline = new InlineLexer(src.links, this.options, this.renderer);
19298       this.tokens = src.reverse();
19299     
19300       var out = '';
19301       while (this.next()) {
19302         out += this.tok();
19303       }
19304     
19305       return out;
19306     };
19307     
19308     /**
19309      * Next Token
19310      */
19311     
19312     Parser.prototype.next = function() {
19313       return this.token = this.tokens.pop();
19314     };
19315     
19316     /**
19317      * Preview Next Token
19318      */
19319     
19320     Parser.prototype.peek = function() {
19321       return this.tokens[this.tokens.length - 1] || 0;
19322     };
19323     
19324     /**
19325      * Parse Text Tokens
19326      */
19327     
19328     Parser.prototype.parseText = function() {
19329       var body = this.token.text;
19330     
19331       while (this.peek().type === 'text') {
19332         body += '\n' + this.next().text;
19333       }
19334     
19335       return this.inline.output(body);
19336     };
19337     
19338     /**
19339      * Parse Current Token
19340      */
19341     
19342     Parser.prototype.tok = function() {
19343       switch (this.token.type) {
19344         case 'space': {
19345           return '';
19346         }
19347         case 'hr': {
19348           return this.renderer.hr();
19349         }
19350         case 'heading': {
19351           return this.renderer.heading(
19352             this.inline.output(this.token.text),
19353             this.token.depth,
19354             this.token.text);
19355         }
19356         case 'code': {
19357           return this.renderer.code(this.token.text,
19358             this.token.lang,
19359             this.token.escaped);
19360         }
19361         case 'table': {
19362           var header = ''
19363             , body = ''
19364             , i
19365             , row
19366             , cell
19367             , flags
19368             , j;
19369     
19370           // header
19371           cell = '';
19372           for (i = 0; i < this.token.header.length; i++) {
19373             flags = { header: true, align: this.token.align[i] };
19374             cell += this.renderer.tablecell(
19375               this.inline.output(this.token.header[i]),
19376               { header: true, align: this.token.align[i] }
19377             );
19378           }
19379           header += this.renderer.tablerow(cell);
19380     
19381           for (i = 0; i < this.token.cells.length; i++) {
19382             row = this.token.cells[i];
19383     
19384             cell = '';
19385             for (j = 0; j < row.length; j++) {
19386               cell += this.renderer.tablecell(
19387                 this.inline.output(row[j]),
19388                 { header: false, align: this.token.align[j] }
19389               );
19390             }
19391     
19392             body += this.renderer.tablerow(cell);
19393           }
19394           return this.renderer.table(header, body);
19395         }
19396         case 'blockquote_start': {
19397           var body = '';
19398     
19399           while (this.next().type !== 'blockquote_end') {
19400             body += this.tok();
19401           }
19402     
19403           return this.renderer.blockquote(body);
19404         }
19405         case 'list_start': {
19406           var body = ''
19407             , ordered = this.token.ordered;
19408     
19409           while (this.next().type !== 'list_end') {
19410             body += this.tok();
19411           }
19412     
19413           return this.renderer.list(body, ordered);
19414         }
19415         case 'list_item_start': {
19416           var body = '';
19417     
19418           while (this.next().type !== 'list_item_end') {
19419             body += this.token.type === 'text'
19420               ? this.parseText()
19421               : this.tok();
19422           }
19423     
19424           return this.renderer.listitem(body);
19425         }
19426         case 'loose_item_start': {
19427           var body = '';
19428     
19429           while (this.next().type !== 'list_item_end') {
19430             body += this.tok();
19431           }
19432     
19433           return this.renderer.listitem(body);
19434         }
19435         case 'html': {
19436           var html = !this.token.pre && !this.options.pedantic
19437             ? this.inline.output(this.token.text)
19438             : this.token.text;
19439           return this.renderer.html(html);
19440         }
19441         case 'paragraph': {
19442           return this.renderer.paragraph(this.inline.output(this.token.text));
19443         }
19444         case 'text': {
19445           return this.renderer.paragraph(this.parseText());
19446         }
19447       }
19448     };
19449   
19450     
19451     /**
19452      * Marked
19453      */
19454          /**
19455          * eval:var:marked
19456     */
19457     var marked = function (src, opt, callback) {
19458       if (callback || typeof opt === 'function') {
19459         if (!callback) {
19460           callback = opt;
19461           opt = null;
19462         }
19463     
19464         opt = merge({}, marked.defaults, opt || {});
19465     
19466         var highlight = opt.highlight
19467           , tokens
19468           , pending
19469           , i = 0;
19470     
19471         try {
19472           tokens = Lexer.lex(src, opt)
19473         } catch (e) {
19474           return callback(e);
19475         }
19476     
19477         pending = tokens.length;
19478          /**
19479          * eval:var:done
19480     */
19481         var done = function(err) {
19482           if (err) {
19483             opt.highlight = highlight;
19484             return callback(err);
19485           }
19486     
19487           var out;
19488     
19489           try {
19490             out = Parser.parse(tokens, opt);
19491           } catch (e) {
19492             err = e;
19493           }
19494     
19495           opt.highlight = highlight;
19496     
19497           return err
19498             ? callback(err)
19499             : callback(null, out);
19500         };
19501     
19502         if (!highlight || highlight.length < 3) {
19503           return done();
19504         }
19505     
19506         delete opt.highlight;
19507     
19508         if (!pending) { return done(); }
19509     
19510         for (; i < tokens.length; i++) {
19511           (function(token) {
19512             if (token.type !== 'code') {
19513               return --pending || done();
19514             }
19515             return highlight(token.text, token.lang, function(err, code) {
19516               if (err) { return done(err); }
19517               if (code == null || code === token.text) {
19518                 return --pending || done();
19519               }
19520               token.text = code;
19521               token.escaped = true;
19522               --pending || done();
19523             });
19524           })(tokens[i]);
19525         }
19526     
19527         return;
19528       }
19529       try {
19530         if (opt) { opt = merge({}, marked.defaults, opt); }
19531         return Parser.parse(Lexer.lex(src, opt), opt);
19532       } catch (e) {
19533         e.message += '\nPlease report this to https://github.com/chjj/marked.';
19534         if ((opt || marked.defaults).silent) {
19535           return '<p>An error occured:</p><pre>'
19536             + escape(e.message + '', true)
19537             + '</pre>';
19538         }
19539         throw e;
19540       }
19541     }
19542     
19543     /**
19544      * Options
19545      */
19546     
19547     marked.options =
19548     marked.setOptions = function(opt) {
19549       merge(marked.defaults, opt);
19550       return marked;
19551     };
19552     
19553     marked.defaults = {
19554       gfm: true,
19555       tables: true,
19556       breaks: false,
19557       pedantic: false,
19558       sanitize: false,
19559       sanitizer: null,
19560       mangle: true,
19561       smartLists: false,
19562       silent: false,
19563       highlight: null,
19564       langPrefix: 'lang-',
19565       smartypants: false,
19566       headerPrefix: '',
19567       renderer: new Renderer,
19568       xhtml: false
19569     };
19570     
19571     /**
19572      * Expose
19573      */
19574     
19575     marked.Parser = Parser;
19576     marked.parser = Parser.parse;
19577     
19578     marked.Renderer = Renderer;
19579     
19580     marked.Lexer = Lexer;
19581     marked.lexer = Lexer.lex;
19582     
19583     marked.InlineLexer = InlineLexer;
19584     marked.inlineLexer = InlineLexer.output;
19585     
19586     marked.parse = marked;
19587     
19588     Roo.Markdown.marked = marked;
19589
19590 })();/*
19591  * Based on:
19592  * Ext JS Library 1.1.1
19593  * Copyright(c) 2006-2007, Ext JS, LLC.
19594  *
19595  * Originally Released Under LGPL - original licence link has changed is not relivant.
19596  *
19597  * Fork - LGPL
19598  * <script type="text/javascript">
19599  */
19600
19601
19602
19603 /*
19604  * These classes are derivatives of the similarly named classes in the YUI Library.
19605  * The original license:
19606  * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
19607  * Code licensed under the BSD License:
19608  * http://developer.yahoo.net/yui/license.txt
19609  */
19610
19611 (function() {
19612
19613 var Event=Roo.EventManager;
19614 var Dom=Roo.lib.Dom;
19615
19616 /**
19617  * @class Roo.dd.DragDrop
19618  * @extends Roo.util.Observable
19619  * Defines the interface and base operation of items that that can be
19620  * dragged or can be drop targets.  It was designed to be extended, overriding
19621  * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
19622  * Up to three html elements can be associated with a DragDrop instance:
19623  * <ul>
19624  * <li>linked element: the element that is passed into the constructor.
19625  * This is the element which defines the boundaries for interaction with
19626  * other DragDrop objects.</li>
19627  * <li>handle element(s): The drag operation only occurs if the element that
19628  * was clicked matches a handle element.  By default this is the linked
19629  * element, but there are times that you will want only a portion of the
19630  * linked element to initiate the drag operation, and the setHandleElId()
19631  * method provides a way to define this.</li>
19632  * <li>drag element: this represents the element that would be moved along
19633  * with the cursor during a drag operation.  By default, this is the linked
19634  * element itself as in {@link Roo.dd.DD}.  setDragElId() lets you define
19635  * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
19636  * </li>
19637  * </ul>
19638  * This class should not be instantiated until the onload event to ensure that
19639  * the associated elements are available.
19640  * The following would define a DragDrop obj that would interact with any
19641  * other DragDrop obj in the "group1" group:
19642  * <pre>
19643  *  dd = new Roo.dd.DragDrop("div1", "group1");
19644  * </pre>
19645  * Since none of the event handlers have been implemented, nothing would
19646  * actually happen if you were to run the code above.  Normally you would
19647  * override this class or one of the default implementations, but you can
19648  * also override the methods you want on an instance of the class...
19649  * <pre>
19650  *  dd.onDragDrop = function(e, id) {
19651  *  &nbsp;&nbsp;alert("dd was dropped on " + id);
19652  *  }
19653  * </pre>
19654  * @constructor
19655  * @param {String} id of the element that is linked to this instance
19656  * @param {String} sGroup the group of related DragDrop objects
19657  * @param {object} config an object containing configurable attributes
19658  *                Valid properties for DragDrop:
19659  *                    padding, isTarget, maintainOffset, primaryButtonOnly
19660  */
19661 Roo.dd.DragDrop = function(id, sGroup, config) {
19662     if (id) {
19663         this.init(id, sGroup, config);
19664     }
19665     
19666 };
19667
19668 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
19669
19670     /**
19671      * The id of the element associated with this object.  This is what we
19672      * refer to as the "linked element" because the size and position of
19673      * this element is used to determine when the drag and drop objects have
19674      * interacted.
19675      * @property id
19676      * @type String
19677      */
19678     id: null,
19679
19680     /**
19681      * Configuration attributes passed into the constructor
19682      * @property config
19683      * @type object
19684      */
19685     config: null,
19686
19687     /**
19688      * The id of the element that will be dragged.  By default this is same
19689      * as the linked element , but could be changed to another element. Ex:
19690      * Roo.dd.DDProxy
19691      * @property dragElId
19692      * @type String
19693      * @private
19694      */
19695     dragElId: null,
19696
19697     /**
19698      * the id of the element that initiates the drag operation.  By default
19699      * this is the linked element, but could be changed to be a child of this
19700      * element.  This lets us do things like only starting the drag when the
19701      * header element within the linked html element is clicked.
19702      * @property handleElId
19703      * @type String
19704      * @private
19705      */
19706     handleElId: null,
19707
19708     /**
19709      * An associative array of HTML tags that will be ignored if clicked.
19710      * @property invalidHandleTypes
19711      * @type {string: string}
19712      */
19713     invalidHandleTypes: null,
19714
19715     /**
19716      * An associative array of ids for elements that will be ignored if clicked
19717      * @property invalidHandleIds
19718      * @type {string: string}
19719      */
19720     invalidHandleIds: null,
19721
19722     /**
19723      * An indexted array of css class names for elements that will be ignored
19724      * if clicked.
19725      * @property invalidHandleClasses
19726      * @type string[]
19727      */
19728     invalidHandleClasses: null,
19729
19730     /**
19731      * The linked element's absolute X position at the time the drag was
19732      * started
19733      * @property startPageX
19734      * @type int
19735      * @private
19736      */
19737     startPageX: 0,
19738
19739     /**
19740      * The linked element's absolute X position at the time the drag was
19741      * started
19742      * @property startPageY
19743      * @type int
19744      * @private
19745      */
19746     startPageY: 0,
19747
19748     /**
19749      * The group defines a logical collection of DragDrop objects that are
19750      * related.  Instances only get events when interacting with other
19751      * DragDrop object in the same group.  This lets us define multiple
19752      * groups using a single DragDrop subclass if we want.
19753      * @property groups
19754      * @type {string: string}
19755      */
19756     groups: null,
19757
19758     /**
19759      * Individual drag/drop instances can be locked.  This will prevent
19760      * onmousedown start drag.
19761      * @property locked
19762      * @type boolean
19763      * @private
19764      */
19765     locked: false,
19766
19767     /**
19768      * Lock this instance
19769      * @method lock
19770      */
19771     lock: function() { this.locked = true; },
19772
19773     /**
19774      * Unlock this instace
19775      * @method unlock
19776      */
19777     unlock: function() { this.locked = false; },
19778
19779     /**
19780      * By default, all insances can be a drop target.  This can be disabled by
19781      * setting isTarget to false.
19782      * @method isTarget
19783      * @type boolean
19784      */
19785     isTarget: true,
19786
19787     /**
19788      * The padding configured for this drag and drop object for calculating
19789      * the drop zone intersection with this object.
19790      * @method padding
19791      * @type int[]
19792      */
19793     padding: null,
19794
19795     /**
19796      * Cached reference to the linked element
19797      * @property _domRef
19798      * @private
19799      */
19800     _domRef: null,
19801
19802     /**
19803      * Internal typeof flag
19804      * @property __ygDragDrop
19805      * @private
19806      */
19807     __ygDragDrop: true,
19808
19809     /**
19810      * Set to true when horizontal contraints are applied
19811      * @property constrainX
19812      * @type boolean
19813      * @private
19814      */
19815     constrainX: false,
19816
19817     /**
19818      * Set to true when vertical contraints are applied
19819      * @property constrainY
19820      * @type boolean
19821      * @private
19822      */
19823     constrainY: false,
19824
19825     /**
19826      * The left constraint
19827      * @property minX
19828      * @type int
19829      * @private
19830      */
19831     minX: 0,
19832
19833     /**
19834      * The right constraint
19835      * @property maxX
19836      * @type int
19837      * @private
19838      */
19839     maxX: 0,
19840
19841     /**
19842      * The up constraint
19843      * @property minY
19844      * @type int
19845      * @type int
19846      * @private
19847      */
19848     minY: 0,
19849
19850     /**
19851      * The down constraint
19852      * @property maxY
19853      * @type int
19854      * @private
19855      */
19856     maxY: 0,
19857
19858     /**
19859      * Maintain offsets when we resetconstraints.  Set to true when you want
19860      * the position of the element relative to its parent to stay the same
19861      * when the page changes
19862      *
19863      * @property maintainOffset
19864      * @type boolean
19865      */
19866     maintainOffset: false,
19867
19868     /**
19869      * Array of pixel locations the element will snap to if we specified a
19870      * horizontal graduation/interval.  This array is generated automatically
19871      * when you define a tick interval.
19872      * @property xTicks
19873      * @type int[]
19874      */
19875     xTicks: null,
19876
19877     /**
19878      * Array of pixel locations the element will snap to if we specified a
19879      * vertical graduation/interval.  This array is generated automatically
19880      * when you define a tick interval.
19881      * @property yTicks
19882      * @type int[]
19883      */
19884     yTicks: null,
19885
19886     /**
19887      * By default the drag and drop instance will only respond to the primary
19888      * button click (left button for a right-handed mouse).  Set to true to
19889      * allow drag and drop to start with any mouse click that is propogated
19890      * by the browser
19891      * @property primaryButtonOnly
19892      * @type boolean
19893      */
19894     primaryButtonOnly: true,
19895
19896     /**
19897      * The availabe property is false until the linked dom element is accessible.
19898      * @property available
19899      * @type boolean
19900      */
19901     available: false,
19902
19903     /**
19904      * By default, drags can only be initiated if the mousedown occurs in the
19905      * region the linked element is.  This is done in part to work around a
19906      * bug in some browsers that mis-report the mousedown if the previous
19907      * mouseup happened outside of the window.  This property is set to true
19908      * if outer handles are defined.
19909      *
19910      * @property hasOuterHandles
19911      * @type boolean
19912      * @default false
19913      */
19914     hasOuterHandles: false,
19915
19916     /**
19917      * Code that executes immediately before the startDrag event
19918      * @method b4StartDrag
19919      * @private
19920      */
19921     b4StartDrag: function(x, y) { },
19922
19923     /**
19924      * Abstract method called after a drag/drop object is clicked
19925      * and the drag or mousedown time thresholds have beeen met.
19926      * @method startDrag
19927      * @param {int} X click location
19928      * @param {int} Y click location
19929      */
19930     startDrag: function(x, y) { /* override this */ },
19931
19932     /**
19933      * Code that executes immediately before the onDrag event
19934      * @method b4Drag
19935      * @private
19936      */
19937     b4Drag: function(e) { },
19938
19939     /**
19940      * Abstract method called during the onMouseMove event while dragging an
19941      * object.
19942      * @method onDrag
19943      * @param {Event} e the mousemove event
19944      */
19945     onDrag: function(e) { /* override this */ },
19946
19947     /**
19948      * Abstract method called when this element fist begins hovering over
19949      * another DragDrop obj
19950      * @method onDragEnter
19951      * @param {Event} e the mousemove event
19952      * @param {String|DragDrop[]} id In POINT mode, the element
19953      * id this is hovering over.  In INTERSECT mode, an array of one or more
19954      * dragdrop items being hovered over.
19955      */
19956     onDragEnter: function(e, id) { /* override this */ },
19957
19958     /**
19959      * Code that executes immediately before the onDragOver event
19960      * @method b4DragOver
19961      * @private
19962      */
19963     b4DragOver: function(e) { },
19964
19965     /**
19966      * Abstract method called when this element is hovering over another
19967      * DragDrop obj
19968      * @method onDragOver
19969      * @param {Event} e the mousemove event
19970      * @param {String|DragDrop[]} id In POINT mode, the element
19971      * id this is hovering over.  In INTERSECT mode, an array of dd items
19972      * being hovered over.
19973      */
19974     onDragOver: function(e, id) { /* override this */ },
19975
19976     /**
19977      * Code that executes immediately before the onDragOut event
19978      * @method b4DragOut
19979      * @private
19980      */
19981     b4DragOut: function(e) { },
19982
19983     /**
19984      * Abstract method called when we are no longer hovering over an element
19985      * @method onDragOut
19986      * @param {Event} e the mousemove event
19987      * @param {String|DragDrop[]} id In POINT mode, the element
19988      * id this was hovering over.  In INTERSECT mode, an array of dd items
19989      * that the mouse is no longer over.
19990      */
19991     onDragOut: function(e, id) { /* override this */ },
19992
19993     /**
19994      * Code that executes immediately before the onDragDrop event
19995      * @method b4DragDrop
19996      * @private
19997      */
19998     b4DragDrop: function(e) { },
19999
20000     /**
20001      * Abstract method called when this item is dropped on another DragDrop
20002      * obj
20003      * @method onDragDrop
20004      * @param {Event} e the mouseup event
20005      * @param {String|DragDrop[]} id In POINT mode, the element
20006      * id this was dropped on.  In INTERSECT mode, an array of dd items this
20007      * was dropped on.
20008      */
20009     onDragDrop: function(e, id) { /* override this */ },
20010
20011     /**
20012      * Abstract method called when this item is dropped on an area with no
20013      * drop target
20014      * @method onInvalidDrop
20015      * @param {Event} e the mouseup event
20016      */
20017     onInvalidDrop: function(e) { /* override this */ },
20018
20019     /**
20020      * Code that executes immediately before the endDrag event
20021      * @method b4EndDrag
20022      * @private
20023      */
20024     b4EndDrag: function(e) { },
20025
20026     /**
20027      * Fired when we are done dragging the object
20028      * @method endDrag
20029      * @param {Event} e the mouseup event
20030      */
20031     endDrag: function(e) { /* override this */ },
20032
20033     /**
20034      * Code executed immediately before the onMouseDown event
20035      * @method b4MouseDown
20036      * @param {Event} e the mousedown event
20037      * @private
20038      */
20039     b4MouseDown: function(e) {  },
20040
20041     /**
20042      * Event handler that fires when a drag/drop obj gets a mousedown
20043      * @method onMouseDown
20044      * @param {Event} e the mousedown event
20045      */
20046     onMouseDown: function(e) { /* override this */ },
20047
20048     /**
20049      * Event handler that fires when a drag/drop obj gets a mouseup
20050      * @method onMouseUp
20051      * @param {Event} e the mouseup event
20052      */
20053     onMouseUp: function(e) { /* override this */ },
20054
20055     /**
20056      * Override the onAvailable method to do what is needed after the initial
20057      * position was determined.
20058      * @method onAvailable
20059      */
20060     onAvailable: function () {
20061     },
20062
20063     /*
20064      * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
20065      * @type Object
20066      */
20067     defaultPadding : {left:0, right:0, top:0, bottom:0},
20068
20069     /*
20070      * Initializes the drag drop object's constraints to restrict movement to a certain element.
20071  *
20072  * Usage:
20073  <pre><code>
20074  var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
20075                 { dragElId: "existingProxyDiv" });
20076  dd.startDrag = function(){
20077      this.constrainTo("parent-id");
20078  };
20079  </code></pre>
20080  * Or you can initalize it using the {@link Roo.Element} object:
20081  <pre><code>
20082  Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
20083      startDrag : function(){
20084          this.constrainTo("parent-id");
20085      }
20086  });
20087  </code></pre>
20088      * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
20089      * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
20090      * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
20091      * an object containing the sides to pad. For example: {right:10, bottom:10}
20092      * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
20093      */
20094     constrainTo : function(constrainTo, pad, inContent){
20095         if(typeof pad == "number"){
20096             pad = {left: pad, right:pad, top:pad, bottom:pad};
20097         }
20098         pad = pad || this.defaultPadding;
20099         var b = Roo.get(this.getEl()).getBox();
20100         var ce = Roo.get(constrainTo);
20101         var s = ce.getScroll();
20102         var c, cd = ce.dom;
20103         if(cd == document.body){
20104             c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
20105         }else{
20106             xy = ce.getXY();
20107             c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
20108         }
20109
20110
20111         var topSpace = b.y - c.y;
20112         var leftSpace = b.x - c.x;
20113
20114         this.resetConstraints();
20115         this.setXConstraint(leftSpace - (pad.left||0), // left
20116                 c.width - leftSpace - b.width - (pad.right||0) //right
20117         );
20118         this.setYConstraint(topSpace - (pad.top||0), //top
20119                 c.height - topSpace - b.height - (pad.bottom||0) //bottom
20120         );
20121     },
20122
20123     /**
20124      * Returns a reference to the linked element
20125      * @method getEl
20126      * @return {HTMLElement} the html element
20127      */
20128     getEl: function() {
20129         if (!this._domRef) {
20130             this._domRef = Roo.getDom(this.id);
20131         }
20132
20133         return this._domRef;
20134     },
20135
20136     /**
20137      * Returns a reference to the actual element to drag.  By default this is
20138      * the same as the html element, but it can be assigned to another
20139      * element. An example of this can be found in Roo.dd.DDProxy
20140      * @method getDragEl
20141      * @return {HTMLElement} the html element
20142      */
20143     getDragEl: function() {
20144         return Roo.getDom(this.dragElId);
20145     },
20146
20147     /**
20148      * Sets up the DragDrop object.  Must be called in the constructor of any
20149      * Roo.dd.DragDrop subclass
20150      * @method init
20151      * @param id the id of the linked element
20152      * @param {String} sGroup the group of related items
20153      * @param {object} config configuration attributes
20154      */
20155     init: function(id, sGroup, config) {
20156         this.initTarget(id, sGroup, config);
20157         if (!Roo.isTouch) {
20158             Event.on(this.id, "mousedown", this.handleMouseDown, this);
20159         }
20160         Event.on(this.id, "touchstart", this.handleMouseDown, this);
20161         // Event.on(this.id, "selectstart", Event.preventDefault);
20162     },
20163
20164     /**
20165      * Initializes Targeting functionality only... the object does not
20166      * get a mousedown handler.
20167      * @method initTarget
20168      * @param id the id of the linked element
20169      * @param {String} sGroup the group of related items
20170      * @param {object} config configuration attributes
20171      */
20172     initTarget: function(id, sGroup, config) {
20173
20174         // configuration attributes
20175         this.config = config || {};
20176
20177         // create a local reference to the drag and drop manager
20178         this.DDM = Roo.dd.DDM;
20179         // initialize the groups array
20180         this.groups = {};
20181
20182         // assume that we have an element reference instead of an id if the
20183         // parameter is not a string
20184         if (typeof id !== "string") {
20185             id = Roo.id(id);
20186         }
20187
20188         // set the id
20189         this.id = id;
20190
20191         // add to an interaction group
20192         this.addToGroup((sGroup) ? sGroup : "default");
20193
20194         // We don't want to register this as the handle with the manager
20195         // so we just set the id rather than calling the setter.
20196         this.handleElId = id;
20197
20198         // the linked element is the element that gets dragged by default
20199         this.setDragElId(id);
20200
20201         // by default, clicked anchors will not start drag operations.
20202         this.invalidHandleTypes = { A: "A" };
20203         this.invalidHandleIds = {};
20204         this.invalidHandleClasses = [];
20205
20206         this.applyConfig();
20207
20208         this.handleOnAvailable();
20209     },
20210
20211     /**
20212      * Applies the configuration parameters that were passed into the constructor.
20213      * This is supposed to happen at each level through the inheritance chain.  So
20214      * a DDProxy implentation will execute apply config on DDProxy, DD, and
20215      * DragDrop in order to get all of the parameters that are available in
20216      * each object.
20217      * @method applyConfig
20218      */
20219     applyConfig: function() {
20220
20221         // configurable properties:
20222         //    padding, isTarget, maintainOffset, primaryButtonOnly
20223         this.padding           = this.config.padding || [0, 0, 0, 0];
20224         this.isTarget          = (this.config.isTarget !== false);
20225         this.maintainOffset    = (this.config.maintainOffset);
20226         this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
20227
20228     },
20229
20230     /**
20231      * Executed when the linked element is available
20232      * @method handleOnAvailable
20233      * @private
20234      */
20235     handleOnAvailable: function() {
20236         this.available = true;
20237         this.resetConstraints();
20238         this.onAvailable();
20239     },
20240
20241      /**
20242      * Configures the padding for the target zone in px.  Effectively expands
20243      * (or reduces) the virtual object size for targeting calculations.
20244      * Supports css-style shorthand; if only one parameter is passed, all sides
20245      * will have that padding, and if only two are passed, the top and bottom
20246      * will have the first param, the left and right the second.
20247      * @method setPadding
20248      * @param {int} iTop    Top pad
20249      * @param {int} iRight  Right pad
20250      * @param {int} iBot    Bot pad
20251      * @param {int} iLeft   Left pad
20252      */
20253     setPadding: function(iTop, iRight, iBot, iLeft) {
20254         // this.padding = [iLeft, iRight, iTop, iBot];
20255         if (!iRight && 0 !== iRight) {
20256             this.padding = [iTop, iTop, iTop, iTop];
20257         } else if (!iBot && 0 !== iBot) {
20258             this.padding = [iTop, iRight, iTop, iRight];
20259         } else {
20260             this.padding = [iTop, iRight, iBot, iLeft];
20261         }
20262     },
20263
20264     /**
20265      * Stores the initial placement of the linked element.
20266      * @method setInitialPosition
20267      * @param {int} diffX   the X offset, default 0
20268      * @param {int} diffY   the Y offset, default 0
20269      */
20270     setInitPosition: function(diffX, diffY) {
20271         var el = this.getEl();
20272
20273         if (!this.DDM.verifyEl(el)) {
20274             return;
20275         }
20276
20277         var dx = diffX || 0;
20278         var dy = diffY || 0;
20279
20280         var p = Dom.getXY( el );
20281
20282         this.initPageX = p[0] - dx;
20283         this.initPageY = p[1] - dy;
20284
20285         this.lastPageX = p[0];
20286         this.lastPageY = p[1];
20287
20288
20289         this.setStartPosition(p);
20290     },
20291
20292     /**
20293      * Sets the start position of the element.  This is set when the obj
20294      * is initialized, the reset when a drag is started.
20295      * @method setStartPosition
20296      * @param pos current position (from previous lookup)
20297      * @private
20298      */
20299     setStartPosition: function(pos) {
20300         var p = pos || Dom.getXY( this.getEl() );
20301         this.deltaSetXY = null;
20302
20303         this.startPageX = p[0];
20304         this.startPageY = p[1];
20305     },
20306
20307     /**
20308      * Add this instance to a group of related drag/drop objects.  All
20309      * instances belong to at least one group, and can belong to as many
20310      * groups as needed.
20311      * @method addToGroup
20312      * @param sGroup {string} the name of the group
20313      */
20314     addToGroup: function(sGroup) {
20315         this.groups[sGroup] = true;
20316         this.DDM.regDragDrop(this, sGroup);
20317     },
20318
20319     /**
20320      * Remove's this instance from the supplied interaction group
20321      * @method removeFromGroup
20322      * @param {string}  sGroup  The group to drop
20323      */
20324     removeFromGroup: function(sGroup) {
20325         if (this.groups[sGroup]) {
20326             delete this.groups[sGroup];
20327         }
20328
20329         this.DDM.removeDDFromGroup(this, sGroup);
20330     },
20331
20332     /**
20333      * Allows you to specify that an element other than the linked element
20334      * will be moved with the cursor during a drag
20335      * @method setDragElId
20336      * @param id {string} the id of the element that will be used to initiate the drag
20337      */
20338     setDragElId: function(id) {
20339         this.dragElId = id;
20340     },
20341
20342     /**
20343      * Allows you to specify a child of the linked element that should be
20344      * used to initiate the drag operation.  An example of this would be if
20345      * you have a content div with text and links.  Clicking anywhere in the
20346      * content area would normally start the drag operation.  Use this method
20347      * to specify that an element inside of the content div is the element
20348      * that starts the drag operation.
20349      * @method setHandleElId
20350      * @param id {string} the id of the element that will be used to
20351      * initiate the drag.
20352      */
20353     setHandleElId: function(id) {
20354         if (typeof id !== "string") {
20355             id = Roo.id(id);
20356         }
20357         this.handleElId = id;
20358         this.DDM.regHandle(this.id, id);
20359     },
20360
20361     /**
20362      * Allows you to set an element outside of the linked element as a drag
20363      * handle
20364      * @method setOuterHandleElId
20365      * @param id the id of the element that will be used to initiate the drag
20366      */
20367     setOuterHandleElId: function(id) {
20368         if (typeof id !== "string") {
20369             id = Roo.id(id);
20370         }
20371         Event.on(id, "mousedown",
20372                 this.handleMouseDown, this);
20373         this.setHandleElId(id);
20374
20375         this.hasOuterHandles = true;
20376     },
20377
20378     /**
20379      * Remove all drag and drop hooks for this element
20380      * @method unreg
20381      */
20382     unreg: function() {
20383         Event.un(this.id, "mousedown",
20384                 this.handleMouseDown);
20385         Event.un(this.id, "touchstart",
20386                 this.handleMouseDown);
20387         this._domRef = null;
20388         this.DDM._remove(this);
20389     },
20390
20391     destroy : function(){
20392         this.unreg();
20393     },
20394
20395     /**
20396      * Returns true if this instance is locked, or the drag drop mgr is locked
20397      * (meaning that all drag/drop is disabled on the page.)
20398      * @method isLocked
20399      * @return {boolean} true if this obj or all drag/drop is locked, else
20400      * false
20401      */
20402     isLocked: function() {
20403         return (this.DDM.isLocked() || this.locked);
20404     },
20405
20406     /**
20407      * Fired when this object is clicked
20408      * @method handleMouseDown
20409      * @param {Event} e
20410      * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
20411      * @private
20412      */
20413     handleMouseDown: function(e, oDD){
20414      
20415         if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
20416             //Roo.log('not touch/ button !=0');
20417             return;
20418         }
20419         if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
20420             return; // double touch..
20421         }
20422         
20423
20424         if (this.isLocked()) {
20425             //Roo.log('locked');
20426             return;
20427         }
20428
20429         this.DDM.refreshCache(this.groups);
20430 //        Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
20431         var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
20432         if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) )  {
20433             //Roo.log('no outer handes or not over target');
20434                 // do nothing.
20435         } else {
20436 //            Roo.log('check validator');
20437             if (this.clickValidator(e)) {
20438 //                Roo.log('validate success');
20439                 // set the initial element position
20440                 this.setStartPosition();
20441
20442
20443                 this.b4MouseDown(e);
20444                 this.onMouseDown(e);
20445
20446                 this.DDM.handleMouseDown(e, this);
20447
20448                 this.DDM.stopEvent(e);
20449             } else {
20450
20451
20452             }
20453         }
20454     },
20455
20456     clickValidator: function(e) {
20457         var target = e.getTarget();
20458         return ( this.isValidHandleChild(target) &&
20459                     (this.id == this.handleElId ||
20460                         this.DDM.handleWasClicked(target, this.id)) );
20461     },
20462
20463     /**
20464      * Allows you to specify a tag name that should not start a drag operation
20465      * when clicked.  This is designed to facilitate embedding links within a
20466      * drag handle that do something other than start the drag.
20467      * @method addInvalidHandleType
20468      * @param {string} tagName the type of element to exclude
20469      */
20470     addInvalidHandleType: function(tagName) {
20471         var type = tagName.toUpperCase();
20472         this.invalidHandleTypes[type] = type;
20473     },
20474
20475     /**
20476      * Lets you to specify an element id for a child of a drag handle
20477      * that should not initiate a drag
20478      * @method addInvalidHandleId
20479      * @param {string} id the element id of the element you wish to ignore
20480      */
20481     addInvalidHandleId: function(id) {
20482         if (typeof id !== "string") {
20483             id = Roo.id(id);
20484         }
20485         this.invalidHandleIds[id] = id;
20486     },
20487
20488     /**
20489      * Lets you specify a css class of elements that will not initiate a drag
20490      * @method addInvalidHandleClass
20491      * @param {string} cssClass the class of the elements you wish to ignore
20492      */
20493     addInvalidHandleClass: function(cssClass) {
20494         this.invalidHandleClasses.push(cssClass);
20495     },
20496
20497     /**
20498      * Unsets an excluded tag name set by addInvalidHandleType
20499      * @method removeInvalidHandleType
20500      * @param {string} tagName the type of element to unexclude
20501      */
20502     removeInvalidHandleType: function(tagName) {
20503         var type = tagName.toUpperCase();
20504         // this.invalidHandleTypes[type] = null;
20505         delete this.invalidHandleTypes[type];
20506     },
20507
20508     /**
20509      * Unsets an invalid handle id
20510      * @method removeInvalidHandleId
20511      * @param {string} id the id of the element to re-enable
20512      */
20513     removeInvalidHandleId: function(id) {
20514         if (typeof id !== "string") {
20515             id = Roo.id(id);
20516         }
20517         delete this.invalidHandleIds[id];
20518     },
20519
20520     /**
20521      * Unsets an invalid css class
20522      * @method removeInvalidHandleClass
20523      * @param {string} cssClass the class of the element(s) you wish to
20524      * re-enable
20525      */
20526     removeInvalidHandleClass: function(cssClass) {
20527         for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
20528             if (this.invalidHandleClasses[i] == cssClass) {
20529                 delete this.invalidHandleClasses[i];
20530             }
20531         }
20532     },
20533
20534     /**
20535      * Checks the tag exclusion list to see if this click should be ignored
20536      * @method isValidHandleChild
20537      * @param {HTMLElement} node the HTMLElement to evaluate
20538      * @return {boolean} true if this is a valid tag type, false if not
20539      */
20540     isValidHandleChild: function(node) {
20541
20542         var valid = true;
20543         // var n = (node.nodeName == "#text") ? node.parentNode : node;
20544         var nodeName;
20545         try {
20546             nodeName = node.nodeName.toUpperCase();
20547         } catch(e) {
20548             nodeName = node.nodeName;
20549         }
20550         valid = valid && !this.invalidHandleTypes[nodeName];
20551         valid = valid && !this.invalidHandleIds[node.id];
20552
20553         for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
20554             valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
20555         }
20556
20557
20558         return valid;
20559
20560     },
20561
20562     /**
20563      * Create the array of horizontal tick marks if an interval was specified
20564      * in setXConstraint().
20565      * @method setXTicks
20566      * @private
20567      */
20568     setXTicks: function(iStartX, iTickSize) {
20569         this.xTicks = [];
20570         this.xTickSize = iTickSize;
20571
20572         var tickMap = {};
20573
20574         for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
20575             if (!tickMap[i]) {
20576                 this.xTicks[this.xTicks.length] = i;
20577                 tickMap[i] = true;
20578             }
20579         }
20580
20581         for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
20582             if (!tickMap[i]) {
20583                 this.xTicks[this.xTicks.length] = i;
20584                 tickMap[i] = true;
20585             }
20586         }
20587
20588         this.xTicks.sort(this.DDM.numericSort) ;
20589     },
20590
20591     /**
20592      * Create the array of vertical tick marks if an interval was specified in
20593      * setYConstraint().
20594      * @method setYTicks
20595      * @private
20596      */
20597     setYTicks: function(iStartY, iTickSize) {
20598         this.yTicks = [];
20599         this.yTickSize = iTickSize;
20600
20601         var tickMap = {};
20602
20603         for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
20604             if (!tickMap[i]) {
20605                 this.yTicks[this.yTicks.length] = i;
20606                 tickMap[i] = true;
20607             }
20608         }
20609
20610         for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
20611             if (!tickMap[i]) {
20612                 this.yTicks[this.yTicks.length] = i;
20613                 tickMap[i] = true;
20614             }
20615         }
20616
20617         this.yTicks.sort(this.DDM.numericSort) ;
20618     },
20619
20620     /**
20621      * By default, the element can be dragged any place on the screen.  Use
20622      * this method to limit the horizontal travel of the element.  Pass in
20623      * 0,0 for the parameters if you want to lock the drag to the y axis.
20624      * @method setXConstraint
20625      * @param {int} iLeft the number of pixels the element can move to the left
20626      * @param {int} iRight the number of pixels the element can move to the
20627      * right
20628      * @param {int} iTickSize optional parameter for specifying that the
20629      * element
20630      * should move iTickSize pixels at a time.
20631      */
20632     setXConstraint: function(iLeft, iRight, iTickSize) {
20633         this.leftConstraint = iLeft;
20634         this.rightConstraint = iRight;
20635
20636         this.minX = this.initPageX - iLeft;
20637         this.maxX = this.initPageX + iRight;
20638         if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
20639
20640         this.constrainX = true;
20641     },
20642
20643     /**
20644      * Clears any constraints applied to this instance.  Also clears ticks
20645      * since they can't exist independent of a constraint at this time.
20646      * @method clearConstraints
20647      */
20648     clearConstraints: function() {
20649         this.constrainX = false;
20650         this.constrainY = false;
20651         this.clearTicks();
20652     },
20653
20654     /**
20655      * Clears any tick interval defined for this instance
20656      * @method clearTicks
20657      */
20658     clearTicks: function() {
20659         this.xTicks = null;
20660         this.yTicks = null;
20661         this.xTickSize = 0;
20662         this.yTickSize = 0;
20663     },
20664
20665     /**
20666      * By default, the element can be dragged any place on the screen.  Set
20667      * this to limit the vertical travel of the element.  Pass in 0,0 for the
20668      * parameters if you want to lock the drag to the x axis.
20669      * @method setYConstraint
20670      * @param {int} iUp the number of pixels the element can move up
20671      * @param {int} iDown the number of pixels the element can move down
20672      * @param {int} iTickSize optional parameter for specifying that the
20673      * element should move iTickSize pixels at a time.
20674      */
20675     setYConstraint: function(iUp, iDown, iTickSize) {
20676         this.topConstraint = iUp;
20677         this.bottomConstraint = iDown;
20678
20679         this.minY = this.initPageY - iUp;
20680         this.maxY = this.initPageY + iDown;
20681         if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
20682
20683         this.constrainY = true;
20684
20685     },
20686
20687     /**
20688      * resetConstraints must be called if you manually reposition a dd element.
20689      * @method resetConstraints
20690      * @param {boolean} maintainOffset
20691      */
20692     resetConstraints: function() {
20693
20694
20695         // Maintain offsets if necessary
20696         if (this.initPageX || this.initPageX === 0) {
20697             // figure out how much this thing has moved
20698             var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
20699             var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
20700
20701             this.setInitPosition(dx, dy);
20702
20703         // This is the first time we have detected the element's position
20704         } else {
20705             this.setInitPosition();
20706         }
20707
20708         if (this.constrainX) {
20709             this.setXConstraint( this.leftConstraint,
20710                                  this.rightConstraint,
20711                                  this.xTickSize        );
20712         }
20713
20714         if (this.constrainY) {
20715             this.setYConstraint( this.topConstraint,
20716                                  this.bottomConstraint,
20717                                  this.yTickSize         );
20718         }
20719     },
20720
20721     /**
20722      * Normally the drag element is moved pixel by pixel, but we can specify
20723      * that it move a number of pixels at a time.  This method resolves the
20724      * location when we have it set up like this.
20725      * @method getTick
20726      * @param {int} val where we want to place the object
20727      * @param {int[]} tickArray sorted array of valid points
20728      * @return {int} the closest tick
20729      * @private
20730      */
20731     getTick: function(val, tickArray) {
20732
20733         if (!tickArray) {
20734             // If tick interval is not defined, it is effectively 1 pixel,
20735             // so we return the value passed to us.
20736             return val;
20737         } else if (tickArray[0] >= val) {
20738             // The value is lower than the first tick, so we return the first
20739             // tick.
20740             return tickArray[0];
20741         } else {
20742             for (var i=0, len=tickArray.length; i<len; ++i) {
20743                 var next = i + 1;
20744                 if (tickArray[next] && tickArray[next] >= val) {
20745                     var diff1 = val - tickArray[i];
20746                     var diff2 = tickArray[next] - val;
20747                     return (diff2 > diff1) ? tickArray[i] : tickArray[next];
20748                 }
20749             }
20750
20751             // The value is larger than the last tick, so we return the last
20752             // tick.
20753             return tickArray[tickArray.length - 1];
20754         }
20755     },
20756
20757     /**
20758      * toString method
20759      * @method toString
20760      * @return {string} string representation of the dd obj
20761      */
20762     toString: function() {
20763         return ("DragDrop " + this.id);
20764     }
20765
20766 });
20767
20768 })();
20769 /*
20770  * Based on:
20771  * Ext JS Library 1.1.1
20772  * Copyright(c) 2006-2007, Ext JS, LLC.
20773  *
20774  * Originally Released Under LGPL - original licence link has changed is not relivant.
20775  *
20776  * Fork - LGPL
20777  * <script type="text/javascript">
20778  */
20779
20780
20781 /**
20782  * The drag and drop utility provides a framework for building drag and drop
20783  * applications.  In addition to enabling drag and drop for specific elements,
20784  * the drag and drop elements are tracked by the manager class, and the
20785  * interactions between the various elements are tracked during the drag and
20786  * the implementing code is notified about these important moments.
20787  */
20788
20789 // Only load the library once.  Rewriting the manager class would orphan
20790 // existing drag and drop instances.
20791 if (!Roo.dd.DragDropMgr) {
20792
20793 /**
20794  * @class Roo.dd.DragDropMgr
20795  * DragDropMgr is a singleton that tracks the element interaction for
20796  * all DragDrop items in the window.  Generally, you will not call
20797  * this class directly, but it does have helper methods that could
20798  * be useful in your DragDrop implementations.
20799  * @static
20800  */
20801 Roo.dd.DragDropMgr = function() {
20802
20803     var Event = Roo.EventManager;
20804
20805     return {
20806
20807         /**
20808          * Two dimensional Array of registered DragDrop objects.  The first
20809          * dimension is the DragDrop item group, the second the DragDrop
20810          * object.
20811          * @property ids
20812          * @type {string: string}
20813          * @private
20814          * @static
20815          */
20816         ids: {},
20817
20818         /**
20819          * Array of element ids defined as drag handles.  Used to determine
20820          * if the element that generated the mousedown event is actually the
20821          * handle and not the html element itself.
20822          * @property handleIds
20823          * @type {string: string}
20824          * @private
20825          * @static
20826          */
20827         handleIds: {},
20828
20829         /**
20830          * the DragDrop object that is currently being dragged
20831          * @property dragCurrent
20832          * @type DragDrop
20833          * @private
20834          * @static
20835          **/
20836         dragCurrent: null,
20837
20838         /**
20839          * the DragDrop object(s) that are being hovered over
20840          * @property dragOvers
20841          * @type Array
20842          * @private
20843          * @static
20844          */
20845         dragOvers: {},
20846
20847         /**
20848          * the X distance between the cursor and the object being dragged
20849          * @property deltaX
20850          * @type int
20851          * @private
20852          * @static
20853          */
20854         deltaX: 0,
20855
20856         /**
20857          * the Y distance between the cursor and the object being dragged
20858          * @property deltaY
20859          * @type int
20860          * @private
20861          * @static
20862          */
20863         deltaY: 0,
20864
20865         /**
20866          * Flag to determine if we should prevent the default behavior of the
20867          * events we define. By default this is true, but this can be set to
20868          * false if you need the default behavior (not recommended)
20869          * @property preventDefault
20870          * @type boolean
20871          * @static
20872          */
20873         preventDefault: true,
20874
20875         /**
20876          * Flag to determine if we should stop the propagation of the events
20877          * we generate. This is true by default but you may want to set it to
20878          * false if the html element contains other features that require the
20879          * mouse click.
20880          * @property stopPropagation
20881          * @type boolean
20882          * @static
20883          */
20884         stopPropagation: true,
20885
20886         /**
20887          * Internal flag that is set to true when drag and drop has been
20888          * intialized
20889          * @property initialized
20890          * @private
20891          * @static
20892          */
20893         initalized: false,
20894
20895         /**
20896          * All drag and drop can be disabled.
20897          * @property locked
20898          * @private
20899          * @static
20900          */
20901         locked: false,
20902
20903         /**
20904          * Called the first time an element is registered.
20905          * @method init
20906          * @private
20907          * @static
20908          */
20909         init: function() {
20910             this.initialized = true;
20911         },
20912
20913         /**
20914          * In point mode, drag and drop interaction is defined by the
20915          * location of the cursor during the drag/drop
20916          * @property POINT
20917          * @type int
20918          * @static
20919          */
20920         POINT: 0,
20921
20922         /**
20923          * In intersect mode, drag and drop interactio nis defined by the
20924          * overlap of two or more drag and drop objects.
20925          * @property INTERSECT
20926          * @type int
20927          * @static
20928          */
20929         INTERSECT: 1,
20930
20931         /**
20932          * The current drag and drop mode.  Default: POINT
20933          * @property mode
20934          * @type int
20935          * @static
20936          */
20937         mode: 0,
20938
20939         /**
20940          * Runs method on all drag and drop objects
20941          * @method _execOnAll
20942          * @private
20943          * @static
20944          */
20945         _execOnAll: function(sMethod, args) {
20946             for (var i in this.ids) {
20947                 for (var j in this.ids[i]) {
20948                     var oDD = this.ids[i][j];
20949                     if (! this.isTypeOfDD(oDD)) {
20950                         continue;
20951                     }
20952                     oDD[sMethod].apply(oDD, args);
20953                 }
20954             }
20955         },
20956
20957         /**
20958          * Drag and drop initialization.  Sets up the global event handlers
20959          * @method _onLoad
20960          * @private
20961          * @static
20962          */
20963         _onLoad: function() {
20964
20965             this.init();
20966
20967             if (!Roo.isTouch) {
20968                 Event.on(document, "mouseup",   this.handleMouseUp, this, true);
20969                 Event.on(document, "mousemove", this.handleMouseMove, this, true);
20970             }
20971             Event.on(document, "touchend",   this.handleMouseUp, this, true);
20972             Event.on(document, "touchmove", this.handleMouseMove, this, true);
20973             
20974             Event.on(window,   "unload",    this._onUnload, this, true);
20975             Event.on(window,   "resize",    this._onResize, this, true);
20976             // Event.on(window,   "mouseout",    this._test);
20977
20978         },
20979
20980         /**
20981          * Reset constraints on all drag and drop objs
20982          * @method _onResize
20983          * @private
20984          * @static
20985          */
20986         _onResize: function(e) {
20987             this._execOnAll("resetConstraints", []);
20988         },
20989
20990         /**
20991          * Lock all drag and drop functionality
20992          * @method lock
20993          * @static
20994          */
20995         lock: function() { this.locked = true; },
20996
20997         /**
20998          * Unlock all drag and drop functionality
20999          * @method unlock
21000          * @static
21001          */
21002         unlock: function() { this.locked = false; },
21003
21004         /**
21005          * Is drag and drop locked?
21006          * @method isLocked
21007          * @return {boolean} True if drag and drop is locked, false otherwise.
21008          * @static
21009          */
21010         isLocked: function() { return this.locked; },
21011
21012         /**
21013          * Location cache that is set for all drag drop objects when a drag is
21014          * initiated, cleared when the drag is finished.
21015          * @property locationCache
21016          * @private
21017          * @static
21018          */
21019         locationCache: {},
21020
21021         /**
21022          * Set useCache to false if you want to force object the lookup of each
21023          * drag and drop linked element constantly during a drag.
21024          * @property useCache
21025          * @type boolean
21026          * @static
21027          */
21028         useCache: true,
21029
21030         /**
21031          * The number of pixels that the mouse needs to move after the
21032          * mousedown before the drag is initiated.  Default=3;
21033          * @property clickPixelThresh
21034          * @type int
21035          * @static
21036          */
21037         clickPixelThresh: 3,
21038
21039         /**
21040          * The number of milliseconds after the mousedown event to initiate the
21041          * drag if we don't get a mouseup event. Default=1000
21042          * @property clickTimeThresh
21043          * @type int
21044          * @static
21045          */
21046         clickTimeThresh: 350,
21047
21048         /**
21049          * Flag that indicates that either the drag pixel threshold or the
21050          * mousdown time threshold has been met
21051          * @property dragThreshMet
21052          * @type boolean
21053          * @private
21054          * @static
21055          */
21056         dragThreshMet: false,
21057
21058         /**
21059          * Timeout used for the click time threshold
21060          * @property clickTimeout
21061          * @type Object
21062          * @private
21063          * @static
21064          */
21065         clickTimeout: null,
21066
21067         /**
21068          * The X position of the mousedown event stored for later use when a
21069          * drag threshold is met.
21070          * @property startX
21071          * @type int
21072          * @private
21073          * @static
21074          */
21075         startX: 0,
21076
21077         /**
21078          * The Y position of the mousedown event stored for later use when a
21079          * drag threshold is met.
21080          * @property startY
21081          * @type int
21082          * @private
21083          * @static
21084          */
21085         startY: 0,
21086
21087         /**
21088          * Each DragDrop instance must be registered with the DragDropMgr.
21089          * This is executed in DragDrop.init()
21090          * @method regDragDrop
21091          * @param {DragDrop} oDD the DragDrop object to register
21092          * @param {String} sGroup the name of the group this element belongs to
21093          * @static
21094          */
21095         regDragDrop: function(oDD, sGroup) {
21096             if (!this.initialized) { this.init(); }
21097
21098             if (!this.ids[sGroup]) {
21099                 this.ids[sGroup] = {};
21100             }
21101             this.ids[sGroup][oDD.id] = oDD;
21102         },
21103
21104         /**
21105          * Removes the supplied dd instance from the supplied group. Executed
21106          * by DragDrop.removeFromGroup, so don't call this function directly.
21107          * @method removeDDFromGroup
21108          * @private
21109          * @static
21110          */
21111         removeDDFromGroup: function(oDD, sGroup) {
21112             if (!this.ids[sGroup]) {
21113                 this.ids[sGroup] = {};
21114             }
21115
21116             var obj = this.ids[sGroup];
21117             if (obj && obj[oDD.id]) {
21118                 delete obj[oDD.id];
21119             }
21120         },
21121
21122         /**
21123          * Unregisters a drag and drop item.  This is executed in
21124          * DragDrop.unreg, use that method instead of calling this directly.
21125          * @method _remove
21126          * @private
21127          * @static
21128          */
21129         _remove: function(oDD) {
21130             for (var g in oDD.groups) {
21131                 if (g && this.ids[g][oDD.id]) {
21132                     delete this.ids[g][oDD.id];
21133                 }
21134             }
21135             delete this.handleIds[oDD.id];
21136         },
21137
21138         /**
21139          * Each DragDrop handle element must be registered.  This is done
21140          * automatically when executing DragDrop.setHandleElId()
21141          * @method regHandle
21142          * @param {String} sDDId the DragDrop id this element is a handle for
21143          * @param {String} sHandleId the id of the element that is the drag
21144          * handle
21145          * @static
21146          */
21147         regHandle: function(sDDId, sHandleId) {
21148             if (!this.handleIds[sDDId]) {
21149                 this.handleIds[sDDId] = {};
21150             }
21151             this.handleIds[sDDId][sHandleId] = sHandleId;
21152         },
21153
21154         /**
21155          * Utility function to determine if a given element has been
21156          * registered as a drag drop item.
21157          * @method isDragDrop
21158          * @param {String} id the element id to check
21159          * @return {boolean} true if this element is a DragDrop item,
21160          * false otherwise
21161          * @static
21162          */
21163         isDragDrop: function(id) {
21164             return ( this.getDDById(id) ) ? true : false;
21165         },
21166
21167         /**
21168          * Returns the drag and drop instances that are in all groups the
21169          * passed in instance belongs to.
21170          * @method getRelated
21171          * @param {DragDrop} p_oDD the obj to get related data for
21172          * @param {boolean} bTargetsOnly if true, only return targetable objs
21173          * @return {DragDrop[]} the related instances
21174          * @static
21175          */
21176         getRelated: function(p_oDD, bTargetsOnly) {
21177             var oDDs = [];
21178             for (var i in p_oDD.groups) {
21179                 for (j in this.ids[i]) {
21180                     var dd = this.ids[i][j];
21181                     if (! this.isTypeOfDD(dd)) {
21182                         continue;
21183                     }
21184                     if (!bTargetsOnly || dd.isTarget) {
21185                         oDDs[oDDs.length] = dd;
21186                     }
21187                 }
21188             }
21189
21190             return oDDs;
21191         },
21192
21193         /**
21194          * Returns true if the specified dd target is a legal target for
21195          * the specifice drag obj
21196          * @method isLegalTarget
21197          * @param {DragDrop} the drag obj
21198          * @param {DragDrop} the target
21199          * @return {boolean} true if the target is a legal target for the
21200          * dd obj
21201          * @static
21202          */
21203         isLegalTarget: function (oDD, oTargetDD) {
21204             var targets = this.getRelated(oDD, true);
21205             for (var i=0, len=targets.length;i<len;++i) {
21206                 if (targets[i].id == oTargetDD.id) {
21207                     return true;
21208                 }
21209             }
21210
21211             return false;
21212         },
21213
21214         /**
21215          * My goal is to be able to transparently determine if an object is
21216          * typeof DragDrop, and the exact subclass of DragDrop.  typeof
21217          * returns "object", oDD.constructor.toString() always returns
21218          * "DragDrop" and not the name of the subclass.  So for now it just
21219          * evaluates a well-known variable in DragDrop.
21220          * @method isTypeOfDD
21221          * @param {Object} the object to evaluate
21222          * @return {boolean} true if typeof oDD = DragDrop
21223          * @static
21224          */
21225         isTypeOfDD: function (oDD) {
21226             return (oDD && oDD.__ygDragDrop);
21227         },
21228
21229         /**
21230          * Utility function to determine if a given element has been
21231          * registered as a drag drop handle for the given Drag Drop object.
21232          * @method isHandle
21233          * @param {String} id the element id to check
21234          * @return {boolean} true if this element is a DragDrop handle, false
21235          * otherwise
21236          * @static
21237          */
21238         isHandle: function(sDDId, sHandleId) {
21239             return ( this.handleIds[sDDId] &&
21240                             this.handleIds[sDDId][sHandleId] );
21241         },
21242
21243         /**
21244          * Returns the DragDrop instance for a given id
21245          * @method getDDById
21246          * @param {String} id the id of the DragDrop object
21247          * @return {DragDrop} the drag drop object, null if it is not found
21248          * @static
21249          */
21250         getDDById: function(id) {
21251             for (var i in this.ids) {
21252                 if (this.ids[i][id]) {
21253                     return this.ids[i][id];
21254                 }
21255             }
21256             return null;
21257         },
21258
21259         /**
21260          * Fired after a registered DragDrop object gets the mousedown event.
21261          * Sets up the events required to track the object being dragged
21262          * @method handleMouseDown
21263          * @param {Event} e the event
21264          * @param oDD the DragDrop object being dragged
21265          * @private
21266          * @static
21267          */
21268         handleMouseDown: function(e, oDD) {
21269             if(Roo.QuickTips){
21270                 Roo.QuickTips.disable();
21271             }
21272             this.currentTarget = e.getTarget();
21273
21274             this.dragCurrent = oDD;
21275
21276             var el = oDD.getEl();
21277
21278             // track start position
21279             this.startX = e.getPageX();
21280             this.startY = e.getPageY();
21281
21282             this.deltaX = this.startX - el.offsetLeft;
21283             this.deltaY = this.startY - el.offsetTop;
21284
21285             this.dragThreshMet = false;
21286
21287             this.clickTimeout = setTimeout(
21288                     function() {
21289                         var DDM = Roo.dd.DDM;
21290                         DDM.startDrag(DDM.startX, DDM.startY);
21291                     },
21292                     this.clickTimeThresh );
21293         },
21294
21295         /**
21296          * Fired when either the drag pixel threshol or the mousedown hold
21297          * time threshold has been met.
21298          * @method startDrag
21299          * @param x {int} the X position of the original mousedown
21300          * @param y {int} the Y position of the original mousedown
21301          * @static
21302          */
21303         startDrag: function(x, y) {
21304             clearTimeout(this.clickTimeout);
21305             if (this.dragCurrent) {
21306                 this.dragCurrent.b4StartDrag(x, y);
21307                 this.dragCurrent.startDrag(x, y);
21308             }
21309             this.dragThreshMet = true;
21310         },
21311
21312         /**
21313          * Internal function to handle the mouseup event.  Will be invoked
21314          * from the context of the document.
21315          * @method handleMouseUp
21316          * @param {Event} e the event
21317          * @private
21318          * @static
21319          */
21320         handleMouseUp: function(e) {
21321
21322             if(Roo.QuickTips){
21323                 Roo.QuickTips.enable();
21324             }
21325             if (! this.dragCurrent) {
21326                 return;
21327             }
21328
21329             clearTimeout(this.clickTimeout);
21330
21331             if (this.dragThreshMet) {
21332                 this.fireEvents(e, true);
21333             } else {
21334             }
21335
21336             this.stopDrag(e);
21337
21338             this.stopEvent(e);
21339         },
21340
21341         /**
21342          * Utility to stop event propagation and event default, if these
21343          * features are turned on.
21344          * @method stopEvent
21345          * @param {Event} e the event as returned by this.getEvent()
21346          * @static
21347          */
21348         stopEvent: function(e){
21349             if(this.stopPropagation) {
21350                 e.stopPropagation();
21351             }
21352
21353             if (this.preventDefault) {
21354                 e.preventDefault();
21355             }
21356         },
21357
21358         /**
21359          * Internal function to clean up event handlers after the drag
21360          * operation is complete
21361          * @method stopDrag
21362          * @param {Event} e the event
21363          * @private
21364          * @static
21365          */
21366         stopDrag: function(e) {
21367             // Fire the drag end event for the item that was dragged
21368             if (this.dragCurrent) {
21369                 if (this.dragThreshMet) {
21370                     this.dragCurrent.b4EndDrag(e);
21371                     this.dragCurrent.endDrag(e);
21372                 }
21373
21374                 this.dragCurrent.onMouseUp(e);
21375             }
21376
21377             this.dragCurrent = null;
21378             this.dragOvers = {};
21379         },
21380
21381         /**
21382          * Internal function to handle the mousemove event.  Will be invoked
21383          * from the context of the html element.
21384          *
21385          * @TODO figure out what we can do about mouse events lost when the
21386          * user drags objects beyond the window boundary.  Currently we can
21387          * detect this in internet explorer by verifying that the mouse is
21388          * down during the mousemove event.  Firefox doesn't give us the
21389          * button state on the mousemove event.
21390          * @method handleMouseMove
21391          * @param {Event} e the event
21392          * @private
21393          * @static
21394          */
21395         handleMouseMove: function(e) {
21396             if (! this.dragCurrent) {
21397                 return true;
21398             }
21399
21400             // var button = e.which || e.button;
21401
21402             // check for IE mouseup outside of page boundary
21403             if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
21404                 this.stopEvent(e);
21405                 return this.handleMouseUp(e);
21406             }
21407
21408             if (!this.dragThreshMet) {
21409                 var diffX = Math.abs(this.startX - e.getPageX());
21410                 var diffY = Math.abs(this.startY - e.getPageY());
21411                 if (diffX > this.clickPixelThresh ||
21412                             diffY > this.clickPixelThresh) {
21413                     this.startDrag(this.startX, this.startY);
21414                 }
21415             }
21416
21417             if (this.dragThreshMet) {
21418                 this.dragCurrent.b4Drag(e);
21419                 this.dragCurrent.onDrag(e);
21420                 if(!this.dragCurrent.moveOnly){
21421                     this.fireEvents(e, false);
21422                 }
21423             }
21424
21425             this.stopEvent(e);
21426
21427             return true;
21428         },
21429
21430         /**
21431          * Iterates over all of the DragDrop elements to find ones we are
21432          * hovering over or dropping on
21433          * @method fireEvents
21434          * @param {Event} e the event
21435          * @param {boolean} isDrop is this a drop op or a mouseover op?
21436          * @private
21437          * @static
21438          */
21439         fireEvents: function(e, isDrop) {
21440             var dc = this.dragCurrent;
21441
21442             // If the user did the mouse up outside of the window, we could
21443             // get here even though we have ended the drag.
21444             if (!dc || dc.isLocked()) {
21445                 return;
21446             }
21447
21448             var pt = e.getPoint();
21449
21450             // cache the previous dragOver array
21451             var oldOvers = [];
21452
21453             var outEvts   = [];
21454             var overEvts  = [];
21455             var dropEvts  = [];
21456             var enterEvts = [];
21457
21458             // Check to see if the object(s) we were hovering over is no longer
21459             // being hovered over so we can fire the onDragOut event
21460             for (var i in this.dragOvers) {
21461
21462                 var ddo = this.dragOvers[i];
21463
21464                 if (! this.isTypeOfDD(ddo)) {
21465                     continue;
21466                 }
21467
21468                 if (! this.isOverTarget(pt, ddo, this.mode)) {
21469                     outEvts.push( ddo );
21470                 }
21471
21472                 oldOvers[i] = true;
21473                 delete this.dragOvers[i];
21474             }
21475
21476             for (var sGroup in dc.groups) {
21477
21478                 if ("string" != typeof sGroup) {
21479                     continue;
21480                 }
21481
21482                 for (i in this.ids[sGroup]) {
21483                     var oDD = this.ids[sGroup][i];
21484                     if (! this.isTypeOfDD(oDD)) {
21485                         continue;
21486                     }
21487
21488                     if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
21489                         if (this.isOverTarget(pt, oDD, this.mode)) {
21490                             // look for drop interactions
21491                             if (isDrop) {
21492                                 dropEvts.push( oDD );
21493                             // look for drag enter and drag over interactions
21494                             } else {
21495
21496                                 // initial drag over: dragEnter fires
21497                                 if (!oldOvers[oDD.id]) {
21498                                     enterEvts.push( oDD );
21499                                 // subsequent drag overs: dragOver fires
21500                                 } else {
21501                                     overEvts.push( oDD );
21502                                 }
21503
21504                                 this.dragOvers[oDD.id] = oDD;
21505                             }
21506                         }
21507                     }
21508                 }
21509             }
21510
21511             if (this.mode) {
21512                 if (outEvts.length) {
21513                     dc.b4DragOut(e, outEvts);
21514                     dc.onDragOut(e, outEvts);
21515                 }
21516
21517                 if (enterEvts.length) {
21518                     dc.onDragEnter(e, enterEvts);
21519                 }
21520
21521                 if (overEvts.length) {
21522                     dc.b4DragOver(e, overEvts);
21523                     dc.onDragOver(e, overEvts);
21524                 }
21525
21526                 if (dropEvts.length) {
21527                     dc.b4DragDrop(e, dropEvts);
21528                     dc.onDragDrop(e, dropEvts);
21529                 }
21530
21531             } else {
21532                 // fire dragout events
21533                 var len = 0;
21534                 for (i=0, len=outEvts.length; i<len; ++i) {
21535                     dc.b4DragOut(e, outEvts[i].id);
21536                     dc.onDragOut(e, outEvts[i].id);
21537                 }
21538
21539                 // fire enter events
21540                 for (i=0,len=enterEvts.length; i<len; ++i) {
21541                     // dc.b4DragEnter(e, oDD.id);
21542                     dc.onDragEnter(e, enterEvts[i].id);
21543                 }
21544
21545                 // fire over events
21546                 for (i=0,len=overEvts.length; i<len; ++i) {
21547                     dc.b4DragOver(e, overEvts[i].id);
21548                     dc.onDragOver(e, overEvts[i].id);
21549                 }
21550
21551                 // fire drop events
21552                 for (i=0, len=dropEvts.length; i<len; ++i) {
21553                     dc.b4DragDrop(e, dropEvts[i].id);
21554                     dc.onDragDrop(e, dropEvts[i].id);
21555                 }
21556
21557             }
21558
21559             // notify about a drop that did not find a target
21560             if (isDrop && !dropEvts.length) {
21561                 dc.onInvalidDrop(e);
21562             }
21563
21564         },
21565
21566         /**
21567          * Helper function for getting the best match from the list of drag
21568          * and drop objects returned by the drag and drop events when we are
21569          * in INTERSECT mode.  It returns either the first object that the
21570          * cursor is over, or the object that has the greatest overlap with
21571          * the dragged element.
21572          * @method getBestMatch
21573          * @param  {DragDrop[]} dds The array of drag and drop objects
21574          * targeted
21575          * @return {DragDrop}       The best single match
21576          * @static
21577          */
21578         getBestMatch: function(dds) {
21579             var winner = null;
21580             // Return null if the input is not what we expect
21581             //if (!dds || !dds.length || dds.length == 0) {
21582                // winner = null;
21583             // If there is only one item, it wins
21584             //} else if (dds.length == 1) {
21585
21586             var len = dds.length;
21587
21588             if (len == 1) {
21589                 winner = dds[0];
21590             } else {
21591                 // Loop through the targeted items
21592                 for (var i=0; i<len; ++i) {
21593                     var dd = dds[i];
21594                     // If the cursor is over the object, it wins.  If the
21595                     // cursor is over multiple matches, the first one we come
21596                     // to wins.
21597                     if (dd.cursorIsOver) {
21598                         winner = dd;
21599                         break;
21600                     // Otherwise the object with the most overlap wins
21601                     } else {
21602                         if (!winner ||
21603                             winner.overlap.getArea() < dd.overlap.getArea()) {
21604                             winner = dd;
21605                         }
21606                     }
21607                 }
21608             }
21609
21610             return winner;
21611         },
21612
21613         /**
21614          * Refreshes the cache of the top-left and bottom-right points of the
21615          * drag and drop objects in the specified group(s).  This is in the
21616          * format that is stored in the drag and drop instance, so typical
21617          * usage is:
21618          * <code>
21619          * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
21620          * </code>
21621          * Alternatively:
21622          * <code>
21623          * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
21624          * </code>
21625          * @TODO this really should be an indexed array.  Alternatively this
21626          * method could accept both.
21627          * @method refreshCache
21628          * @param {Object} groups an associative array of groups to refresh
21629          * @static
21630          */
21631         refreshCache: function(groups) {
21632             for (var sGroup in groups) {
21633                 if ("string" != typeof sGroup) {
21634                     continue;
21635                 }
21636                 for (var i in this.ids[sGroup]) {
21637                     var oDD = this.ids[sGroup][i];
21638
21639                     if (this.isTypeOfDD(oDD)) {
21640                     // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
21641                         var loc = this.getLocation(oDD);
21642                         if (loc) {
21643                             this.locationCache[oDD.id] = loc;
21644                         } else {
21645                             delete this.locationCache[oDD.id];
21646                             // this will unregister the drag and drop object if
21647                             // the element is not in a usable state
21648                             // oDD.unreg();
21649                         }
21650                     }
21651                 }
21652             }
21653         },
21654
21655         /**
21656          * This checks to make sure an element exists and is in the DOM.  The
21657          * main purpose is to handle cases where innerHTML is used to remove
21658          * drag and drop objects from the DOM.  IE provides an 'unspecified
21659          * error' when trying to access the offsetParent of such an element
21660          * @method verifyEl
21661          * @param {HTMLElement} el the element to check
21662          * @return {boolean} true if the element looks usable
21663          * @static
21664          */
21665         verifyEl: function(el) {
21666             if (el) {
21667                 var parent;
21668                 if(Roo.isIE){
21669                     try{
21670                         parent = el.offsetParent;
21671                     }catch(e){}
21672                 }else{
21673                     parent = el.offsetParent;
21674                 }
21675                 if (parent) {
21676                     return true;
21677                 }
21678             }
21679
21680             return false;
21681         },
21682
21683         /**
21684          * Returns a Region object containing the drag and drop element's position
21685          * and size, including the padding configured for it
21686          * @method getLocation
21687          * @param {DragDrop} oDD the drag and drop object to get the
21688          *                       location for
21689          * @return {Roo.lib.Region} a Region object representing the total area
21690          *                             the element occupies, including any padding
21691          *                             the instance is configured for.
21692          * @static
21693          */
21694         getLocation: function(oDD) {
21695             if (! this.isTypeOfDD(oDD)) {
21696                 return null;
21697             }
21698
21699             var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
21700
21701             try {
21702                 pos= Roo.lib.Dom.getXY(el);
21703             } catch (e) { }
21704
21705             if (!pos) {
21706                 return null;
21707             }
21708
21709             x1 = pos[0];
21710             x2 = x1 + el.offsetWidth;
21711             y1 = pos[1];
21712             y2 = y1 + el.offsetHeight;
21713
21714             t = y1 - oDD.padding[0];
21715             r = x2 + oDD.padding[1];
21716             b = y2 + oDD.padding[2];
21717             l = x1 - oDD.padding[3];
21718
21719             return new Roo.lib.Region( t, r, b, l );
21720         },
21721
21722         /**
21723          * Checks the cursor location to see if it over the target
21724          * @method isOverTarget
21725          * @param {Roo.lib.Point} pt The point to evaluate
21726          * @param {DragDrop} oTarget the DragDrop object we are inspecting
21727          * @return {boolean} true if the mouse is over the target
21728          * @private
21729          * @static
21730          */
21731         isOverTarget: function(pt, oTarget, intersect) {
21732             // use cache if available
21733             var loc = this.locationCache[oTarget.id];
21734             if (!loc || !this.useCache) {
21735                 loc = this.getLocation(oTarget);
21736                 this.locationCache[oTarget.id] = loc;
21737
21738             }
21739
21740             if (!loc) {
21741                 return false;
21742             }
21743
21744             oTarget.cursorIsOver = loc.contains( pt );
21745
21746             // DragDrop is using this as a sanity check for the initial mousedown
21747             // in this case we are done.  In POINT mode, if the drag obj has no
21748             // contraints, we are also done. Otherwise we need to evaluate the
21749             // location of the target as related to the actual location of the
21750             // dragged element.
21751             var dc = this.dragCurrent;
21752             if (!dc || !dc.getTargetCoord ||
21753                     (!intersect && !dc.constrainX && !dc.constrainY)) {
21754                 return oTarget.cursorIsOver;
21755             }
21756
21757             oTarget.overlap = null;
21758
21759             // Get the current location of the drag element, this is the
21760             // location of the mouse event less the delta that represents
21761             // where the original mousedown happened on the element.  We
21762             // need to consider constraints and ticks as well.
21763             var pos = dc.getTargetCoord(pt.x, pt.y);
21764
21765             var el = dc.getDragEl();
21766             var curRegion = new Roo.lib.Region( pos.y,
21767                                                    pos.x + el.offsetWidth,
21768                                                    pos.y + el.offsetHeight,
21769                                                    pos.x );
21770
21771             var overlap = curRegion.intersect(loc);
21772
21773             if (overlap) {
21774                 oTarget.overlap = overlap;
21775                 return (intersect) ? true : oTarget.cursorIsOver;
21776             } else {
21777                 return false;
21778             }
21779         },
21780
21781         /**
21782          * unload event handler
21783          * @method _onUnload
21784          * @private
21785          * @static
21786          */
21787         _onUnload: function(e, me) {
21788             Roo.dd.DragDropMgr.unregAll();
21789         },
21790
21791         /**
21792          * Cleans up the drag and drop events and objects.
21793          * @method unregAll
21794          * @private
21795          * @static
21796          */
21797         unregAll: function() {
21798
21799             if (this.dragCurrent) {
21800                 this.stopDrag();
21801                 this.dragCurrent = null;
21802             }
21803
21804             this._execOnAll("unreg", []);
21805
21806             for (i in this.elementCache) {
21807                 delete this.elementCache[i];
21808             }
21809
21810             this.elementCache = {};
21811             this.ids = {};
21812         },
21813
21814         /**
21815          * A cache of DOM elements
21816          * @property elementCache
21817          * @private
21818          * @static
21819          */
21820         elementCache: {},
21821
21822         /**
21823          * Get the wrapper for the DOM element specified
21824          * @method getElWrapper
21825          * @param {String} id the id of the element to get
21826          * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
21827          * @private
21828          * @deprecated This wrapper isn't that useful
21829          * @static
21830          */
21831         getElWrapper: function(id) {
21832             var oWrapper = this.elementCache[id];
21833             if (!oWrapper || !oWrapper.el) {
21834                 oWrapper = this.elementCache[id] =
21835                     new this.ElementWrapper(Roo.getDom(id));
21836             }
21837             return oWrapper;
21838         },
21839
21840         /**
21841          * Returns the actual DOM element
21842          * @method getElement
21843          * @param {String} id the id of the elment to get
21844          * @return {Object} The element
21845          * @deprecated use Roo.getDom instead
21846          * @static
21847          */
21848         getElement: function(id) {
21849             return Roo.getDom(id);
21850         },
21851
21852         /**
21853          * Returns the style property for the DOM element (i.e.,
21854          * document.getElById(id).style)
21855          * @method getCss
21856          * @param {String} id the id of the elment to get
21857          * @return {Object} The style property of the element
21858          * @deprecated use Roo.getDom instead
21859          * @static
21860          */
21861         getCss: function(id) {
21862             var el = Roo.getDom(id);
21863             return (el) ? el.style : null;
21864         },
21865
21866         /**
21867          * Inner class for cached elements
21868          * @class DragDropMgr.ElementWrapper
21869          * @for DragDropMgr
21870          * @private
21871          * @deprecated
21872          */
21873         ElementWrapper: function(el) {
21874                 /**
21875                  * The element
21876                  * @property el
21877                  */
21878                 this.el = el || null;
21879                 /**
21880                  * The element id
21881                  * @property id
21882                  */
21883                 this.id = this.el && el.id;
21884                 /**
21885                  * A reference to the style property
21886                  * @property css
21887                  */
21888                 this.css = this.el && el.style;
21889             },
21890
21891         /**
21892          * Returns the X position of an html element
21893          * @method getPosX
21894          * @param el the element for which to get the position
21895          * @return {int} the X coordinate
21896          * @for DragDropMgr
21897          * @deprecated use Roo.lib.Dom.getX instead
21898          * @static
21899          */
21900         getPosX: function(el) {
21901             return Roo.lib.Dom.getX(el);
21902         },
21903
21904         /**
21905          * Returns the Y position of an html element
21906          * @method getPosY
21907          * @param el the element for which to get the position
21908          * @return {int} the Y coordinate
21909          * @deprecated use Roo.lib.Dom.getY instead
21910          * @static
21911          */
21912         getPosY: function(el) {
21913             return Roo.lib.Dom.getY(el);
21914         },
21915
21916         /**
21917          * Swap two nodes.  In IE, we use the native method, for others we
21918          * emulate the IE behavior
21919          * @method swapNode
21920          * @param n1 the first node to swap
21921          * @param n2 the other node to swap
21922          * @static
21923          */
21924         swapNode: function(n1, n2) {
21925             if (n1.swapNode) {
21926                 n1.swapNode(n2);
21927             } else {
21928                 var p = n2.parentNode;
21929                 var s = n2.nextSibling;
21930
21931                 if (s == n1) {
21932                     p.insertBefore(n1, n2);
21933                 } else if (n2 == n1.nextSibling) {
21934                     p.insertBefore(n2, n1);
21935                 } else {
21936                     n1.parentNode.replaceChild(n2, n1);
21937                     p.insertBefore(n1, s);
21938                 }
21939             }
21940         },
21941
21942         /**
21943          * Returns the current scroll position
21944          * @method getScroll
21945          * @private
21946          * @static
21947          */
21948         getScroll: function () {
21949             var t, l, dde=document.documentElement, db=document.body;
21950             if (dde && (dde.scrollTop || dde.scrollLeft)) {
21951                 t = dde.scrollTop;
21952                 l = dde.scrollLeft;
21953             } else if (db) {
21954                 t = db.scrollTop;
21955                 l = db.scrollLeft;
21956             } else {
21957
21958             }
21959             return { top: t, left: l };
21960         },
21961
21962         /**
21963          * Returns the specified element style property
21964          * @method getStyle
21965          * @param {HTMLElement} el          the element
21966          * @param {string}      styleProp   the style property
21967          * @return {string} The value of the style property
21968          * @deprecated use Roo.lib.Dom.getStyle
21969          * @static
21970          */
21971         getStyle: function(el, styleProp) {
21972             return Roo.fly(el).getStyle(styleProp);
21973         },
21974
21975         /**
21976          * Gets the scrollTop
21977          * @method getScrollTop
21978          * @return {int} the document's scrollTop
21979          * @static
21980          */
21981         getScrollTop: function () { return this.getScroll().top; },
21982
21983         /**
21984          * Gets the scrollLeft
21985          * @method getScrollLeft
21986          * @return {int} the document's scrollTop
21987          * @static
21988          */
21989         getScrollLeft: function () { return this.getScroll().left; },
21990
21991         /**
21992          * Sets the x/y position of an element to the location of the
21993          * target element.
21994          * @method moveToEl
21995          * @param {HTMLElement} moveEl      The element to move
21996          * @param {HTMLElement} targetEl    The position reference element
21997          * @static
21998          */
21999         moveToEl: function (moveEl, targetEl) {
22000             var aCoord = Roo.lib.Dom.getXY(targetEl);
22001             Roo.lib.Dom.setXY(moveEl, aCoord);
22002         },
22003
22004         /**
22005          * Numeric array sort function
22006          * @method numericSort
22007          * @static
22008          */
22009         numericSort: function(a, b) { return (a - b); },
22010
22011         /**
22012          * Internal counter
22013          * @property _timeoutCount
22014          * @private
22015          * @static
22016          */
22017         _timeoutCount: 0,
22018
22019         /**
22020          * Trying to make the load order less important.  Without this we get
22021          * an error if this file is loaded before the Event Utility.
22022          * @method _addListeners
22023          * @private
22024          * @static
22025          */
22026         _addListeners: function() {
22027             var DDM = Roo.dd.DDM;
22028             if ( Roo.lib.Event && document ) {
22029                 DDM._onLoad();
22030             } else {
22031                 if (DDM._timeoutCount > 2000) {
22032                 } else {
22033                     setTimeout(DDM._addListeners, 10);
22034                     if (document && document.body) {
22035                         DDM._timeoutCount += 1;
22036                     }
22037                 }
22038             }
22039         },
22040
22041         /**
22042          * Recursively searches the immediate parent and all child nodes for
22043          * the handle element in order to determine wheter or not it was
22044          * clicked.
22045          * @method handleWasClicked
22046          * @param node the html element to inspect
22047          * @static
22048          */
22049         handleWasClicked: function(node, id) {
22050             if (this.isHandle(id, node.id)) {
22051                 return true;
22052             } else {
22053                 // check to see if this is a text node child of the one we want
22054                 var p = node.parentNode;
22055
22056                 while (p) {
22057                     if (this.isHandle(id, p.id)) {
22058                         return true;
22059                     } else {
22060                         p = p.parentNode;
22061                     }
22062                 }
22063             }
22064
22065             return false;
22066         }
22067
22068     };
22069
22070 }();
22071
22072 // shorter alias, save a few bytes
22073 Roo.dd.DDM = Roo.dd.DragDropMgr;
22074 Roo.dd.DDM._addListeners();
22075
22076 }/*
22077  * Based on:
22078  * Ext JS Library 1.1.1
22079  * Copyright(c) 2006-2007, Ext JS, LLC.
22080  *
22081  * Originally Released Under LGPL - original licence link has changed is not relivant.
22082  *
22083  * Fork - LGPL
22084  * <script type="text/javascript">
22085  */
22086
22087 /**
22088  * @class Roo.dd.DD
22089  * A DragDrop implementation where the linked element follows the
22090  * mouse cursor during a drag.
22091  * @extends Roo.dd.DragDrop
22092  * @constructor
22093  * @param {String} id the id of the linked element
22094  * @param {String} sGroup the group of related DragDrop items
22095  * @param {object} config an object containing configurable attributes
22096  *                Valid properties for DD:
22097  *                    scroll
22098  */
22099 Roo.dd.DD = function(id, sGroup, config) {
22100     if (id) {
22101         this.init(id, sGroup, config);
22102     }
22103 };
22104
22105 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
22106
22107     /**
22108      * When set to true, the utility automatically tries to scroll the browser
22109      * window wehn a drag and drop element is dragged near the viewport boundary.
22110      * Defaults to true.
22111      * @property scroll
22112      * @type boolean
22113      */
22114     scroll: true,
22115
22116     /**
22117      * Sets the pointer offset to the distance between the linked element's top
22118      * left corner and the location the element was clicked
22119      * @method autoOffset
22120      * @param {int} iPageX the X coordinate of the click
22121      * @param {int} iPageY the Y coordinate of the click
22122      */
22123     autoOffset: function(iPageX, iPageY) {
22124         var x = iPageX - this.startPageX;
22125         var y = iPageY - this.startPageY;
22126         this.setDelta(x, y);
22127     },
22128
22129     /**
22130      * Sets the pointer offset.  You can call this directly to force the
22131      * offset to be in a particular location (e.g., pass in 0,0 to set it
22132      * to the center of the object)
22133      * @method setDelta
22134      * @param {int} iDeltaX the distance from the left
22135      * @param {int} iDeltaY the distance from the top
22136      */
22137     setDelta: function(iDeltaX, iDeltaY) {
22138         this.deltaX = iDeltaX;
22139         this.deltaY = iDeltaY;
22140     },
22141
22142     /**
22143      * Sets the drag element to the location of the mousedown or click event,
22144      * maintaining the cursor location relative to the location on the element
22145      * that was clicked.  Override this if you want to place the element in a
22146      * location other than where the cursor is.
22147      * @method setDragElPos
22148      * @param {int} iPageX the X coordinate of the mousedown or drag event
22149      * @param {int} iPageY the Y coordinate of the mousedown or drag event
22150      */
22151     setDragElPos: function(iPageX, iPageY) {
22152         // the first time we do this, we are going to check to make sure
22153         // the element has css positioning
22154
22155         var el = this.getDragEl();
22156         this.alignElWithMouse(el, iPageX, iPageY);
22157     },
22158
22159     /**
22160      * Sets the element to the location of the mousedown or click event,
22161      * maintaining the cursor location relative to the location on the element
22162      * that was clicked.  Override this if you want to place the element in a
22163      * location other than where the cursor is.
22164      * @method alignElWithMouse
22165      * @param {HTMLElement} el the element to move
22166      * @param {int} iPageX the X coordinate of the mousedown or drag event
22167      * @param {int} iPageY the Y coordinate of the mousedown or drag event
22168      */
22169     alignElWithMouse: function(el, iPageX, iPageY) {
22170         var oCoord = this.getTargetCoord(iPageX, iPageY);
22171         var fly = el.dom ? el : Roo.fly(el);
22172         if (!this.deltaSetXY) {
22173             var aCoord = [oCoord.x, oCoord.y];
22174             fly.setXY(aCoord);
22175             var newLeft = fly.getLeft(true);
22176             var newTop  = fly.getTop(true);
22177             this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
22178         } else {
22179             fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
22180         }
22181
22182         this.cachePosition(oCoord.x, oCoord.y);
22183         this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
22184         return oCoord;
22185     },
22186
22187     /**
22188      * Saves the most recent position so that we can reset the constraints and
22189      * tick marks on-demand.  We need to know this so that we can calculate the
22190      * number of pixels the element is offset from its original position.
22191      * @method cachePosition
22192      * @param iPageX the current x position (optional, this just makes it so we
22193      * don't have to look it up again)
22194      * @param iPageY the current y position (optional, this just makes it so we
22195      * don't have to look it up again)
22196      */
22197     cachePosition: function(iPageX, iPageY) {
22198         if (iPageX) {
22199             this.lastPageX = iPageX;
22200             this.lastPageY = iPageY;
22201         } else {
22202             var aCoord = Roo.lib.Dom.getXY(this.getEl());
22203             this.lastPageX = aCoord[0];
22204             this.lastPageY = aCoord[1];
22205         }
22206     },
22207
22208     /**
22209      * Auto-scroll the window if the dragged object has been moved beyond the
22210      * visible window boundary.
22211      * @method autoScroll
22212      * @param {int} x the drag element's x position
22213      * @param {int} y the drag element's y position
22214      * @param {int} h the height of the drag element
22215      * @param {int} w the width of the drag element
22216      * @private
22217      */
22218     autoScroll: function(x, y, h, w) {
22219
22220         if (this.scroll) {
22221             // The client height
22222             var clientH = Roo.lib.Dom.getViewWidth();
22223
22224             // The client width
22225             var clientW = Roo.lib.Dom.getViewHeight();
22226
22227             // The amt scrolled down
22228             var st = this.DDM.getScrollTop();
22229
22230             // The amt scrolled right
22231             var sl = this.DDM.getScrollLeft();
22232
22233             // Location of the bottom of the element
22234             var bot = h + y;
22235
22236             // Location of the right of the element
22237             var right = w + x;
22238
22239             // The distance from the cursor to the bottom of the visible area,
22240             // adjusted so that we don't scroll if the cursor is beyond the
22241             // element drag constraints
22242             var toBot = (clientH + st - y - this.deltaY);
22243
22244             // The distance from the cursor to the right of the visible area
22245             var toRight = (clientW + sl - x - this.deltaX);
22246
22247
22248             // How close to the edge the cursor must be before we scroll
22249             // var thresh = (document.all) ? 100 : 40;
22250             var thresh = 40;
22251
22252             // How many pixels to scroll per autoscroll op.  This helps to reduce
22253             // clunky scrolling. IE is more sensitive about this ... it needs this
22254             // value to be higher.
22255             var scrAmt = (document.all) ? 80 : 30;
22256
22257             // Scroll down if we are near the bottom of the visible page and the
22258             // obj extends below the crease
22259             if ( bot > clientH && toBot < thresh ) {
22260                 window.scrollTo(sl, st + scrAmt);
22261             }
22262
22263             // Scroll up if the window is scrolled down and the top of the object
22264             // goes above the top border
22265             if ( y < st && st > 0 && y - st < thresh ) {
22266                 window.scrollTo(sl, st - scrAmt);
22267             }
22268
22269             // Scroll right if the obj is beyond the right border and the cursor is
22270             // near the border.
22271             if ( right > clientW && toRight < thresh ) {
22272                 window.scrollTo(sl + scrAmt, st);
22273             }
22274
22275             // Scroll left if the window has been scrolled to the right and the obj
22276             // extends past the left border
22277             if ( x < sl && sl > 0 && x - sl < thresh ) {
22278                 window.scrollTo(sl - scrAmt, st);
22279             }
22280         }
22281     },
22282
22283     /**
22284      * Finds the location the element should be placed if we want to move
22285      * it to where the mouse location less the click offset would place us.
22286      * @method getTargetCoord
22287      * @param {int} iPageX the X coordinate of the click
22288      * @param {int} iPageY the Y coordinate of the click
22289      * @return an object that contains the coordinates (Object.x and Object.y)
22290      * @private
22291      */
22292     getTargetCoord: function(iPageX, iPageY) {
22293
22294
22295         var x = iPageX - this.deltaX;
22296         var y = iPageY - this.deltaY;
22297
22298         if (this.constrainX) {
22299             if (x < this.minX) { x = this.minX; }
22300             if (x > this.maxX) { x = this.maxX; }
22301         }
22302
22303         if (this.constrainY) {
22304             if (y < this.minY) { y = this.minY; }
22305             if (y > this.maxY) { y = this.maxY; }
22306         }
22307
22308         x = this.getTick(x, this.xTicks);
22309         y = this.getTick(y, this.yTicks);
22310
22311
22312         return {x:x, y:y};
22313     },
22314
22315     /*
22316      * Sets up config options specific to this class. Overrides
22317      * Roo.dd.DragDrop, but all versions of this method through the
22318      * inheritance chain are called
22319      */
22320     applyConfig: function() {
22321         Roo.dd.DD.superclass.applyConfig.call(this);
22322         this.scroll = (this.config.scroll !== false);
22323     },
22324
22325     /*
22326      * Event that fires prior to the onMouseDown event.  Overrides
22327      * Roo.dd.DragDrop.
22328      */
22329     b4MouseDown: function(e) {
22330         // this.resetConstraints();
22331         this.autoOffset(e.getPageX(),
22332                             e.getPageY());
22333     },
22334
22335     /*
22336      * Event that fires prior to the onDrag event.  Overrides
22337      * Roo.dd.DragDrop.
22338      */
22339     b4Drag: function(e) {
22340         this.setDragElPos(e.getPageX(),
22341                             e.getPageY());
22342     },
22343
22344     toString: function() {
22345         return ("DD " + this.id);
22346     }
22347
22348     //////////////////////////////////////////////////////////////////////////
22349     // Debugging ygDragDrop events that can be overridden
22350     //////////////////////////////////////////////////////////////////////////
22351     /*
22352     startDrag: function(x, y) {
22353     },
22354
22355     onDrag: function(e) {
22356     },
22357
22358     onDragEnter: function(e, id) {
22359     },
22360
22361     onDragOver: function(e, id) {
22362     },
22363
22364     onDragOut: function(e, id) {
22365     },
22366
22367     onDragDrop: function(e, id) {
22368     },
22369
22370     endDrag: function(e) {
22371     }
22372
22373     */
22374
22375 });/*
22376  * Based on:
22377  * Ext JS Library 1.1.1
22378  * Copyright(c) 2006-2007, Ext JS, LLC.
22379  *
22380  * Originally Released Under LGPL - original licence link has changed is not relivant.
22381  *
22382  * Fork - LGPL
22383  * <script type="text/javascript">
22384  */
22385
22386 /**
22387  * @class Roo.dd.DDProxy
22388  * A DragDrop implementation that inserts an empty, bordered div into
22389  * the document that follows the cursor during drag operations.  At the time of
22390  * the click, the frame div is resized to the dimensions of the linked html
22391  * element, and moved to the exact location of the linked element.
22392  *
22393  * References to the "frame" element refer to the single proxy element that
22394  * was created to be dragged in place of all DDProxy elements on the
22395  * page.
22396  *
22397  * @extends Roo.dd.DD
22398  * @constructor
22399  * @param {String} id the id of the linked html element
22400  * @param {String} sGroup the group of related DragDrop objects
22401  * @param {object} config an object containing configurable attributes
22402  *                Valid properties for DDProxy in addition to those in DragDrop:
22403  *                   resizeFrame, centerFrame, dragElId
22404  */
22405 Roo.dd.DDProxy = function(id, sGroup, config) {
22406     if (id) {
22407         this.init(id, sGroup, config);
22408         this.initFrame();
22409     }
22410 };
22411
22412 /**
22413  * The default drag frame div id
22414  * @property Roo.dd.DDProxy.dragElId
22415  * @type String
22416  * @static
22417  */
22418 Roo.dd.DDProxy.dragElId = "ygddfdiv";
22419
22420 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
22421
22422     /**
22423      * By default we resize the drag frame to be the same size as the element
22424      * we want to drag (this is to get the frame effect).  We can turn it off
22425      * if we want a different behavior.
22426      * @property resizeFrame
22427      * @type boolean
22428      */
22429     resizeFrame: true,
22430
22431     /**
22432      * By default the frame is positioned exactly where the drag element is, so
22433      * we use the cursor offset provided by Roo.dd.DD.  Another option that works only if
22434      * you do not have constraints on the obj is to have the drag frame centered
22435      * around the cursor.  Set centerFrame to true for this effect.
22436      * @property centerFrame
22437      * @type boolean
22438      */
22439     centerFrame: false,
22440
22441     /**
22442      * Creates the proxy element if it does not yet exist
22443      * @method createFrame
22444      */
22445     createFrame: function() {
22446         var self = this;
22447         var body = document.body;
22448
22449         if (!body || !body.firstChild) {
22450             setTimeout( function() { self.createFrame(); }, 50 );
22451             return;
22452         }
22453
22454         var div = this.getDragEl();
22455
22456         if (!div) {
22457             div    = document.createElement("div");
22458             div.id = this.dragElId;
22459             var s  = div.style;
22460
22461             s.position   = "absolute";
22462             s.visibility = "hidden";
22463             s.cursor     = "move";
22464             s.border     = "2px solid #aaa";
22465             s.zIndex     = 999;
22466
22467             // appendChild can blow up IE if invoked prior to the window load event
22468             // while rendering a table.  It is possible there are other scenarios
22469             // that would cause this to happen as well.
22470             body.insertBefore(div, body.firstChild);
22471         }
22472     },
22473
22474     /**
22475      * Initialization for the drag frame element.  Must be called in the
22476      * constructor of all subclasses
22477      * @method initFrame
22478      */
22479     initFrame: function() {
22480         this.createFrame();
22481     },
22482
22483     applyConfig: function() {
22484         Roo.dd.DDProxy.superclass.applyConfig.call(this);
22485
22486         this.resizeFrame = (this.config.resizeFrame !== false);
22487         this.centerFrame = (this.config.centerFrame);
22488         this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
22489     },
22490
22491     /**
22492      * Resizes the drag frame to the dimensions of the clicked object, positions
22493      * it over the object, and finally displays it
22494      * @method showFrame
22495      * @param {int} iPageX X click position
22496      * @param {int} iPageY Y click position
22497      * @private
22498      */
22499     showFrame: function(iPageX, iPageY) {
22500         var el = this.getEl();
22501         var dragEl = this.getDragEl();
22502         var s = dragEl.style;
22503
22504         this._resizeProxy();
22505
22506         if (this.centerFrame) {
22507             this.setDelta( Math.round(parseInt(s.width,  10)/2),
22508                            Math.round(parseInt(s.height, 10)/2) );
22509         }
22510
22511         this.setDragElPos(iPageX, iPageY);
22512
22513         Roo.fly(dragEl).show();
22514     },
22515
22516     /**
22517      * The proxy is automatically resized to the dimensions of the linked
22518      * element when a drag is initiated, unless resizeFrame is set to false
22519      * @method _resizeProxy
22520      * @private
22521      */
22522     _resizeProxy: function() {
22523         if (this.resizeFrame) {
22524             var el = this.getEl();
22525             Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
22526         }
22527     },
22528
22529     // overrides Roo.dd.DragDrop
22530     b4MouseDown: function(e) {
22531         var x = e.getPageX();
22532         var y = e.getPageY();
22533         this.autoOffset(x, y);
22534         this.setDragElPos(x, y);
22535     },
22536
22537     // overrides Roo.dd.DragDrop
22538     b4StartDrag: function(x, y) {
22539         // show the drag frame
22540         this.showFrame(x, y);
22541     },
22542
22543     // overrides Roo.dd.DragDrop
22544     b4EndDrag: function(e) {
22545         Roo.fly(this.getDragEl()).hide();
22546     },
22547
22548     // overrides Roo.dd.DragDrop
22549     // By default we try to move the element to the last location of the frame.
22550     // This is so that the default behavior mirrors that of Roo.dd.DD.
22551     endDrag: function(e) {
22552
22553         var lel = this.getEl();
22554         var del = this.getDragEl();
22555
22556         // Show the drag frame briefly so we can get its position
22557         del.style.visibility = "";
22558
22559         this.beforeMove();
22560         // Hide the linked element before the move to get around a Safari
22561         // rendering bug.
22562         lel.style.visibility = "hidden";
22563         Roo.dd.DDM.moveToEl(lel, del);
22564         del.style.visibility = "hidden";
22565         lel.style.visibility = "";
22566
22567         this.afterDrag();
22568     },
22569
22570     beforeMove : function(){
22571
22572     },
22573
22574     afterDrag : function(){
22575
22576     },
22577
22578     toString: function() {
22579         return ("DDProxy " + this.id);
22580     }
22581
22582 });
22583 /*
22584  * Based on:
22585  * Ext JS Library 1.1.1
22586  * Copyright(c) 2006-2007, Ext JS, LLC.
22587  *
22588  * Originally Released Under LGPL - original licence link has changed is not relivant.
22589  *
22590  * Fork - LGPL
22591  * <script type="text/javascript">
22592  */
22593
22594  /**
22595  * @class Roo.dd.DDTarget
22596  * A DragDrop implementation that does not move, but can be a drop
22597  * target.  You would get the same result by simply omitting implementation
22598  * for the event callbacks, but this way we reduce the processing cost of the
22599  * event listener and the callbacks.
22600  * @extends Roo.dd.DragDrop
22601  * @constructor
22602  * @param {String} id the id of the element that is a drop target
22603  * @param {String} sGroup the group of related DragDrop objects
22604  * @param {object} config an object containing configurable attributes
22605  *                 Valid properties for DDTarget in addition to those in
22606  *                 DragDrop:
22607  *                    none
22608  */
22609 Roo.dd.DDTarget = function(id, sGroup, config) {
22610     if (id) {
22611         this.initTarget(id, sGroup, config);
22612     }
22613     if (config && (config.listeners || config.events)) { 
22614         Roo.dd.DragDrop.superclass.constructor.call(this,  { 
22615             listeners : config.listeners || {}, 
22616             events : config.events || {} 
22617         });    
22618     }
22619 };
22620
22621 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
22622 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
22623     toString: function() {
22624         return ("DDTarget " + this.id);
22625     }
22626 });
22627 /*
22628  * Based on:
22629  * Ext JS Library 1.1.1
22630  * Copyright(c) 2006-2007, Ext JS, LLC.
22631  *
22632  * Originally Released Under LGPL - original licence link has changed is not relivant.
22633  *
22634  * Fork - LGPL
22635  * <script type="text/javascript">
22636  */
22637  
22638
22639 /**
22640  * @class Roo.dd.ScrollManager
22641  * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
22642  * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
22643  * @static
22644  */
22645 Roo.dd.ScrollManager = function(){
22646     var ddm = Roo.dd.DragDropMgr;
22647     var els = {};
22648     var dragEl = null;
22649     var proc = {};
22650     
22651     
22652     
22653     var onStop = function(e){
22654         dragEl = null;
22655         clearProc();
22656     };
22657     
22658     var triggerRefresh = function(){
22659         if(ddm.dragCurrent){
22660              ddm.refreshCache(ddm.dragCurrent.groups);
22661         }
22662     };
22663     
22664     var doScroll = function(){
22665         if(ddm.dragCurrent){
22666             var dds = Roo.dd.ScrollManager;
22667             if(!dds.animate){
22668                 if(proc.el.scroll(proc.dir, dds.increment)){
22669                     triggerRefresh();
22670                 }
22671             }else{
22672                 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
22673             }
22674         }
22675     };
22676     
22677     var clearProc = function(){
22678         if(proc.id){
22679             clearInterval(proc.id);
22680         }
22681         proc.id = 0;
22682         proc.el = null;
22683         proc.dir = "";
22684     };
22685     
22686     var startProc = function(el, dir){
22687          Roo.log('scroll startproc');
22688         clearProc();
22689         proc.el = el;
22690         proc.dir = dir;
22691         proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
22692     };
22693     
22694     var onFire = function(e, isDrop){
22695        
22696         if(isDrop || !ddm.dragCurrent){ return; }
22697         var dds = Roo.dd.ScrollManager;
22698         if(!dragEl || dragEl != ddm.dragCurrent){
22699             dragEl = ddm.dragCurrent;
22700             // refresh regions on drag start
22701             dds.refreshCache();
22702         }
22703         
22704         var xy = Roo.lib.Event.getXY(e);
22705         var pt = new Roo.lib.Point(xy[0], xy[1]);
22706         for(var id in els){
22707             var el = els[id], r = el._region;
22708             if(r && r.contains(pt) && el.isScrollable()){
22709                 if(r.bottom - pt.y <= dds.thresh){
22710                     if(proc.el != el){
22711                         startProc(el, "down");
22712                     }
22713                     return;
22714                 }else if(r.right - pt.x <= dds.thresh){
22715                     if(proc.el != el){
22716                         startProc(el, "left");
22717                     }
22718                     return;
22719                 }else if(pt.y - r.top <= dds.thresh){
22720                     if(proc.el != el){
22721                         startProc(el, "up");
22722                     }
22723                     return;
22724                 }else if(pt.x - r.left <= dds.thresh){
22725                     if(proc.el != el){
22726                         startProc(el, "right");
22727                     }
22728                     return;
22729                 }
22730             }
22731         }
22732         clearProc();
22733     };
22734     
22735     ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
22736     ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
22737     
22738     return {
22739         /**
22740          * Registers new overflow element(s) to auto scroll
22741          * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
22742          */
22743         register : function(el){
22744             if(el instanceof Array){
22745                 for(var i = 0, len = el.length; i < len; i++) {
22746                         this.register(el[i]);
22747                 }
22748             }else{
22749                 el = Roo.get(el);
22750                 els[el.id] = el;
22751             }
22752             Roo.dd.ScrollManager.els = els;
22753         },
22754         
22755         /**
22756          * Unregisters overflow element(s) so they are no longer scrolled
22757          * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
22758          */
22759         unregister : function(el){
22760             if(el instanceof Array){
22761                 for(var i = 0, len = el.length; i < len; i++) {
22762                         this.unregister(el[i]);
22763                 }
22764             }else{
22765                 el = Roo.get(el);
22766                 delete els[el.id];
22767             }
22768         },
22769         
22770         /**
22771          * The number of pixels from the edge of a container the pointer needs to be to 
22772          * trigger scrolling (defaults to 25)
22773          * @type Number
22774          */
22775         thresh : 25,
22776         
22777         /**
22778          * The number of pixels to scroll in each scroll increment (defaults to 50)
22779          * @type Number
22780          */
22781         increment : 100,
22782         
22783         /**
22784          * The frequency of scrolls in milliseconds (defaults to 500)
22785          * @type Number
22786          */
22787         frequency : 500,
22788         
22789         /**
22790          * True to animate the scroll (defaults to true)
22791          * @type Boolean
22792          */
22793         animate: true,
22794         
22795         /**
22796          * The animation duration in seconds - 
22797          * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
22798          * @type Number
22799          */
22800         animDuration: .4,
22801         
22802         /**
22803          * Manually trigger a cache refresh.
22804          */
22805         refreshCache : function(){
22806             for(var id in els){
22807                 if(typeof els[id] == 'object'){ // for people extending the object prototype
22808                     els[id]._region = els[id].getRegion();
22809                 }
22810             }
22811         }
22812     };
22813 }();/*
22814  * Based on:
22815  * Ext JS Library 1.1.1
22816  * Copyright(c) 2006-2007, Ext JS, LLC.
22817  *
22818  * Originally Released Under LGPL - original licence link has changed is not relivant.
22819  *
22820  * Fork - LGPL
22821  * <script type="text/javascript">
22822  */
22823  
22824
22825 /**
22826  * @class Roo.dd.Registry
22827  * Provides easy access to all drag drop components that are registered on a page.  Items can be retrieved either
22828  * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
22829  * @static
22830  */
22831 Roo.dd.Registry = function(){
22832     var elements = {}; 
22833     var handles = {}; 
22834     var autoIdSeed = 0;
22835
22836     var getId = function(el, autogen){
22837         if(typeof el == "string"){
22838             return el;
22839         }
22840         var id = el.id;
22841         if(!id && autogen !== false){
22842             id = "roodd-" + (++autoIdSeed);
22843             el.id = id;
22844         }
22845         return id;
22846     };
22847     
22848     return {
22849     /**
22850      * Register a drag drop element
22851      * @param {String|HTMLElement} element The id or DOM node to register
22852      * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
22853      * in drag drop operations.  You can populate this object with any arbitrary properties that your own code
22854      * knows how to interpret, plus there are some specific properties known to the Registry that should be
22855      * populated in the data object (if applicable):
22856      * <pre>
22857 Value      Description<br />
22858 ---------  ------------------------------------------<br />
22859 handles    Array of DOM nodes that trigger dragging<br />
22860            for the element being registered<br />
22861 isHandle   True if the element passed in triggers<br />
22862            dragging itself, else false
22863 </pre>
22864      */
22865         register : function(el, data){
22866             data = data || {};
22867             if(typeof el == "string"){
22868                 el = document.getElementById(el);
22869             }
22870             data.ddel = el;
22871             elements[getId(el)] = data;
22872             if(data.isHandle !== false){
22873                 handles[data.ddel.id] = data;
22874             }
22875             if(data.handles){
22876                 var hs = data.handles;
22877                 for(var i = 0, len = hs.length; i < len; i++){
22878                         handles[getId(hs[i])] = data;
22879                 }
22880             }
22881         },
22882
22883     /**
22884      * Unregister a drag drop element
22885      * @param {String|HTMLElement}  element The id or DOM node to unregister
22886      */
22887         unregister : function(el){
22888             var id = getId(el, false);
22889             var data = elements[id];
22890             if(data){
22891                 delete elements[id];
22892                 if(data.handles){
22893                     var hs = data.handles;
22894                     for(var i = 0, len = hs.length; i < len; i++){
22895                         delete handles[getId(hs[i], false)];
22896                     }
22897                 }
22898             }
22899         },
22900
22901     /**
22902      * Returns the handle registered for a DOM Node by id
22903      * @param {String|HTMLElement} id The DOM node or id to look up
22904      * @return {Object} handle The custom handle data
22905      */
22906         getHandle : function(id){
22907             if(typeof id != "string"){ // must be element?
22908                 id = id.id;
22909             }
22910             return handles[id];
22911         },
22912
22913     /**
22914      * Returns the handle that is registered for the DOM node that is the target of the event
22915      * @param {Event} e The event
22916      * @return {Object} handle The custom handle data
22917      */
22918         getHandleFromEvent : function(e){
22919             var t = Roo.lib.Event.getTarget(e);
22920             return t ? handles[t.id] : null;
22921         },
22922
22923     /**
22924      * Returns a custom data object that is registered for a DOM node by id
22925      * @param {String|HTMLElement} id The DOM node or id to look up
22926      * @return {Object} data The custom data
22927      */
22928         getTarget : function(id){
22929             if(typeof id != "string"){ // must be element?
22930                 id = id.id;
22931             }
22932             return elements[id];
22933         },
22934
22935     /**
22936      * Returns a custom data object that is registered for the DOM node that is the target of the event
22937      * @param {Event} e The event
22938      * @return {Object} data The custom data
22939      */
22940         getTargetFromEvent : function(e){
22941             var t = Roo.lib.Event.getTarget(e);
22942             return t ? elements[t.id] || handles[t.id] : null;
22943         }
22944     };
22945 }();/*
22946  * Based on:
22947  * Ext JS Library 1.1.1
22948  * Copyright(c) 2006-2007, Ext JS, LLC.
22949  *
22950  * Originally Released Under LGPL - original licence link has changed is not relivant.
22951  *
22952  * Fork - LGPL
22953  * <script type="text/javascript">
22954  */
22955  
22956
22957 /**
22958  * @class Roo.dd.StatusProxy
22959  * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair.  This is the
22960  * default drag proxy used by all Roo.dd components.
22961  * @constructor
22962  * @param {Object} config
22963  */
22964 Roo.dd.StatusProxy = function(config){
22965     Roo.apply(this, config);
22966     this.id = this.id || Roo.id();
22967     this.el = new Roo.Layer({
22968         dh: {
22969             id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
22970                 {tag: "div", cls: "x-dd-drop-icon"},
22971                 {tag: "div", cls: "x-dd-drag-ghost"}
22972             ]
22973         }, 
22974         shadow: !config || config.shadow !== false
22975     });
22976     this.ghost = Roo.get(this.el.dom.childNodes[1]);
22977     this.dropStatus = this.dropNotAllowed;
22978 };
22979
22980 Roo.dd.StatusProxy.prototype = {
22981     /**
22982      * @cfg {String} dropAllowed
22983      * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
22984      */
22985     dropAllowed : "x-dd-drop-ok",
22986     /**
22987      * @cfg {String} dropNotAllowed
22988      * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
22989      */
22990     dropNotAllowed : "x-dd-drop-nodrop",
22991
22992     /**
22993      * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
22994      * over the current target element.
22995      * @param {String} cssClass The css class for the new drop status indicator image
22996      */
22997     setStatus : function(cssClass){
22998         cssClass = cssClass || this.dropNotAllowed;
22999         if(this.dropStatus != cssClass){
23000             this.el.replaceClass(this.dropStatus, cssClass);
23001             this.dropStatus = cssClass;
23002         }
23003     },
23004
23005     /**
23006      * Resets the status indicator to the default dropNotAllowed value
23007      * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
23008      */
23009     reset : function(clearGhost){
23010         this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
23011         this.dropStatus = this.dropNotAllowed;
23012         if(clearGhost){
23013             this.ghost.update("");
23014         }
23015     },
23016
23017     /**
23018      * Updates the contents of the ghost element
23019      * @param {String} html The html that will replace the current innerHTML of the ghost element
23020      */
23021     update : function(html){
23022         if(typeof html == "string"){
23023             this.ghost.update(html);
23024         }else{
23025             this.ghost.update("");
23026             html.style.margin = "0";
23027             this.ghost.dom.appendChild(html);
23028         }
23029         // ensure float = none set?? cant remember why though.
23030         var el = this.ghost.dom.firstChild;
23031                 if(el){
23032                         Roo.fly(el).setStyle('float', 'none');
23033                 }
23034     },
23035     
23036     /**
23037      * Returns the underlying proxy {@link Roo.Layer}
23038      * @return {Roo.Layer} el
23039     */
23040     getEl : function(){
23041         return this.el;
23042     },
23043
23044     /**
23045      * Returns the ghost element
23046      * @return {Roo.Element} el
23047      */
23048     getGhost : function(){
23049         return this.ghost;
23050     },
23051
23052     /**
23053      * Hides the proxy
23054      * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
23055      */
23056     hide : function(clear){
23057         this.el.hide();
23058         if(clear){
23059             this.reset(true);
23060         }
23061     },
23062
23063     /**
23064      * Stops the repair animation if it's currently running
23065      */
23066     stop : function(){
23067         if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
23068             this.anim.stop();
23069         }
23070     },
23071
23072     /**
23073      * Displays this proxy
23074      */
23075     show : function(){
23076         this.el.show();
23077     },
23078
23079     /**
23080      * Force the Layer to sync its shadow and shim positions to the element
23081      */
23082     sync : function(){
23083         this.el.sync();
23084     },
23085
23086     /**
23087      * Causes the proxy to return to its position of origin via an animation.  Should be called after an
23088      * invalid drop operation by the item being dragged.
23089      * @param {Array} xy The XY position of the element ([x, y])
23090      * @param {Function} callback The function to call after the repair is complete
23091      * @param {Object} scope The scope in which to execute the callback
23092      */
23093     repair : function(xy, callback, scope){
23094         this.callback = callback;
23095         this.scope = scope;
23096         if(xy && this.animRepair !== false){
23097             this.el.addClass("x-dd-drag-repair");
23098             this.el.hideUnders(true);
23099             this.anim = this.el.shift({
23100                 duration: this.repairDuration || .5,
23101                 easing: 'easeOut',
23102                 xy: xy,
23103                 stopFx: true,
23104                 callback: this.afterRepair,
23105                 scope: this
23106             });
23107         }else{
23108             this.afterRepair();
23109         }
23110     },
23111
23112     // private
23113     afterRepair : function(){
23114         this.hide(true);
23115         if(typeof this.callback == "function"){
23116             this.callback.call(this.scope || this);
23117         }
23118         this.callback = null;
23119         this.scope = null;
23120     }
23121 };/*
23122  * Based on:
23123  * Ext JS Library 1.1.1
23124  * Copyright(c) 2006-2007, Ext JS, LLC.
23125  *
23126  * Originally Released Under LGPL - original licence link has changed is not relivant.
23127  *
23128  * Fork - LGPL
23129  * <script type="text/javascript">
23130  */
23131
23132 /**
23133  * @class Roo.dd.DragSource
23134  * @extends Roo.dd.DDProxy
23135  * A simple class that provides the basic implementation needed to make any element draggable.
23136  * @constructor
23137  * @param {String/HTMLElement/Element} el The container element
23138  * @param {Object} config
23139  */
23140 Roo.dd.DragSource = function(el, config){
23141     this.el = Roo.get(el);
23142     this.dragData = {};
23143     
23144     Roo.apply(this, config);
23145     
23146     if(!this.proxy){
23147         this.proxy = new Roo.dd.StatusProxy();
23148     }
23149
23150     Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
23151           {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
23152     
23153     this.dragging = false;
23154 };
23155
23156 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
23157     /**
23158      * @cfg {String} dropAllowed
23159      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
23160      */
23161     dropAllowed : "x-dd-drop-ok",
23162     /**
23163      * @cfg {String} dropNotAllowed
23164      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
23165      */
23166     dropNotAllowed : "x-dd-drop-nodrop",
23167
23168     /**
23169      * Returns the data object associated with this drag source
23170      * @return {Object} data An object containing arbitrary data
23171      */
23172     getDragData : function(e){
23173         return this.dragData;
23174     },
23175
23176     // private
23177     onDragEnter : function(e, id){
23178         var target = Roo.dd.DragDropMgr.getDDById(id);
23179         this.cachedTarget = target;
23180         if(this.beforeDragEnter(target, e, id) !== false){
23181             if(target.isNotifyTarget){
23182                 var status = target.notifyEnter(this, e, this.dragData);
23183                 this.proxy.setStatus(status);
23184             }else{
23185                 this.proxy.setStatus(this.dropAllowed);
23186             }
23187             
23188             if(this.afterDragEnter){
23189                 /**
23190                  * An empty function by default, but provided so that you can perform a custom action
23191                  * when the dragged item enters the drop target by providing an implementation.
23192                  * @param {Roo.dd.DragDrop} target The drop target
23193                  * @param {Event} e The event object
23194                  * @param {String} id The id of the dragged element
23195                  * @method afterDragEnter
23196                  */
23197                 this.afterDragEnter(target, e, id);
23198             }
23199         }
23200     },
23201
23202     /**
23203      * An empty function by default, but provided so that you can perform a custom action
23204      * before the dragged item enters the drop target and optionally cancel the onDragEnter.
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     beforeDragEnter : function(target, e, id){
23211         return true;
23212     },
23213
23214     // private
23215     alignElWithMouse: function() {
23216         Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
23217         this.proxy.sync();
23218     },
23219
23220     // private
23221     onDragOver : function(e, id){
23222         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23223         if(this.beforeDragOver(target, e, id) !== false){
23224             if(target.isNotifyTarget){
23225                 var status = target.notifyOver(this, e, this.dragData);
23226                 this.proxy.setStatus(status);
23227             }
23228
23229             if(this.afterDragOver){
23230                 /**
23231                  * An empty function by default, but provided so that you can perform a custom action
23232                  * while the dragged item is over the drop target by providing an implementation.
23233                  * @param {Roo.dd.DragDrop} target The drop target
23234                  * @param {Event} e The event object
23235                  * @param {String} id The id of the dragged element
23236                  * @method afterDragOver
23237                  */
23238                 this.afterDragOver(target, e, id);
23239             }
23240         }
23241     },
23242
23243     /**
23244      * An empty function by default, but provided so that you can perform a custom action
23245      * while the dragged item is over the drop target and optionally cancel the onDragOver.
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 event is valid, else false to cancel
23250      */
23251     beforeDragOver : function(target, e, id){
23252         return true;
23253     },
23254
23255     // private
23256     onDragOut : function(e, id){
23257         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23258         if(this.beforeDragOut(target, e, id) !== false){
23259             if(target.isNotifyTarget){
23260                 target.notifyOut(this, e, this.dragData);
23261             }
23262             this.proxy.reset();
23263             if(this.afterDragOut){
23264                 /**
23265                  * An empty function by default, but provided so that you can perform a custom action
23266                  * after the dragged item is dragged out of the target without dropping.
23267                  * @param {Roo.dd.DragDrop} target The drop target
23268                  * @param {Event} e The event object
23269                  * @param {String} id The id of the dragged element
23270                  * @method afterDragOut
23271                  */
23272                 this.afterDragOut(target, e, id);
23273             }
23274         }
23275         this.cachedTarget = null;
23276     },
23277
23278     /**
23279      * An empty function by default, but provided so that you can perform a custom action before the dragged
23280      * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
23281      * @param {Roo.dd.DragDrop} target The drop target
23282      * @param {Event} e The event object
23283      * @param {String} id The id of the dragged element
23284      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23285      */
23286     beforeDragOut : function(target, e, id){
23287         return true;
23288     },
23289     
23290     // private
23291     onDragDrop : function(e, id){
23292         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23293         if(this.beforeDragDrop(target, e, id) !== false){
23294             if(target.isNotifyTarget){
23295                 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
23296                     this.onValidDrop(target, e, id);
23297                 }else{
23298                     this.onInvalidDrop(target, e, id);
23299                 }
23300             }else{
23301                 this.onValidDrop(target, e, id);
23302             }
23303             
23304             if(this.afterDragDrop){
23305                 /**
23306                  * An empty function by default, but provided so that you can perform a custom action
23307                  * after a valid drag drop has occurred by providing an implementation.
23308                  * @param {Roo.dd.DragDrop} target The drop target
23309                  * @param {Event} e The event object
23310                  * @param {String} id The id of the dropped element
23311                  * @method afterDragDrop
23312                  */
23313                 this.afterDragDrop(target, e, id);
23314             }
23315         }
23316         delete this.cachedTarget;
23317     },
23318
23319     /**
23320      * An empty function by default, but provided so that you can perform a custom action before the dragged
23321      * item is dropped onto the target and optionally cancel the onDragDrop.
23322      * @param {Roo.dd.DragDrop} target The drop target
23323      * @param {Event} e The event object
23324      * @param {String} id The id of the dragged element
23325      * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
23326      */
23327     beforeDragDrop : function(target, e, id){
23328         return true;
23329     },
23330
23331     // private
23332     onValidDrop : function(target, e, id){
23333         this.hideProxy();
23334         if(this.afterValidDrop){
23335             /**
23336              * An empty function by default, but provided so that you can perform a custom action
23337              * after a valid drop has occurred by providing an implementation.
23338              * @param {Object} target The target DD 
23339              * @param {Event} e The event object
23340              * @param {String} id The id of the dropped element
23341              * @method afterInvalidDrop
23342              */
23343             this.afterValidDrop(target, e, id);
23344         }
23345     },
23346
23347     // private
23348     getRepairXY : function(e, data){
23349         return this.el.getXY();  
23350     },
23351
23352     // private
23353     onInvalidDrop : function(target, e, id){
23354         this.beforeInvalidDrop(target, e, id);
23355         if(this.cachedTarget){
23356             if(this.cachedTarget.isNotifyTarget){
23357                 this.cachedTarget.notifyOut(this, e, this.dragData);
23358             }
23359             this.cacheTarget = null;
23360         }
23361         this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
23362
23363         if(this.afterInvalidDrop){
23364             /**
23365              * An empty function by default, but provided so that you can perform a custom action
23366              * after an invalid drop has occurred by providing an implementation.
23367              * @param {Event} e The event object
23368              * @param {String} id The id of the dropped element
23369              * @method afterInvalidDrop
23370              */
23371             this.afterInvalidDrop(e, id);
23372         }
23373     },
23374
23375     // private
23376     afterRepair : function(){
23377         if(Roo.enableFx){
23378             this.el.highlight(this.hlColor || "c3daf9");
23379         }
23380         this.dragging = false;
23381     },
23382
23383     /**
23384      * An empty function by default, but provided so that you can perform a custom action after an invalid
23385      * drop has occurred.
23386      * @param {Roo.dd.DragDrop} target The drop target
23387      * @param {Event} e The event object
23388      * @param {String} id The id of the dragged element
23389      * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
23390      */
23391     beforeInvalidDrop : function(target, e, id){
23392         return true;
23393     },
23394
23395     // private
23396     handleMouseDown : function(e){
23397         if(this.dragging) {
23398             return;
23399         }
23400         var data = this.getDragData(e);
23401         if(data && this.onBeforeDrag(data, e) !== false){
23402             this.dragData = data;
23403             this.proxy.stop();
23404             Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
23405         } 
23406     },
23407
23408     /**
23409      * An empty function by default, but provided so that you can perform a custom action before the initial
23410      * drag event begins and optionally cancel it.
23411      * @param {Object} data An object containing arbitrary data to be shared with drop targets
23412      * @param {Event} e The event object
23413      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23414      */
23415     onBeforeDrag : function(data, e){
23416         return true;
23417     },
23418
23419     /**
23420      * An empty function by default, but provided so that you can perform a custom action once the initial
23421      * drag event has begun.  The drag cannot be canceled from this function.
23422      * @param {Number} x The x position of the click on the dragged object
23423      * @param {Number} y The y position of the click on the dragged object
23424      */
23425     onStartDrag : Roo.emptyFn,
23426
23427     // private - YUI override
23428     startDrag : function(x, y){
23429         this.proxy.reset();
23430         this.dragging = true;
23431         this.proxy.update("");
23432         this.onInitDrag(x, y);
23433         this.proxy.show();
23434     },
23435
23436     // private
23437     onInitDrag : function(x, y){
23438         var clone = this.el.dom.cloneNode(true);
23439         clone.id = Roo.id(); // prevent duplicate ids
23440         this.proxy.update(clone);
23441         this.onStartDrag(x, y);
23442         return true;
23443     },
23444
23445     /**
23446      * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
23447      * @return {Roo.dd.StatusProxy} proxy The StatusProxy
23448      */
23449     getProxy : function(){
23450         return this.proxy;  
23451     },
23452
23453     /**
23454      * Hides the drag source's {@link Roo.dd.StatusProxy}
23455      */
23456     hideProxy : function(){
23457         this.proxy.hide();  
23458         this.proxy.reset(true);
23459         this.dragging = false;
23460     },
23461
23462     // private
23463     triggerCacheRefresh : function(){
23464         Roo.dd.DDM.refreshCache(this.groups);
23465     },
23466
23467     // private - override to prevent hiding
23468     b4EndDrag: function(e) {
23469     },
23470
23471     // private - override to prevent moving
23472     endDrag : function(e){
23473         this.onEndDrag(this.dragData, e);
23474     },
23475
23476     // private
23477     onEndDrag : function(data, e){
23478     },
23479     
23480     // private - pin to cursor
23481     autoOffset : function(x, y) {
23482         this.setDelta(-12, -20);
23483     }    
23484 });/*
23485  * Based on:
23486  * Ext JS Library 1.1.1
23487  * Copyright(c) 2006-2007, Ext JS, LLC.
23488  *
23489  * Originally Released Under LGPL - original licence link has changed is not relivant.
23490  *
23491  * Fork - LGPL
23492  * <script type="text/javascript">
23493  */
23494
23495
23496 /**
23497  * @class Roo.dd.DropTarget
23498  * @extends Roo.dd.DDTarget
23499  * A simple class that provides the basic implementation needed to make any element a drop target that can have
23500  * draggable items dropped onto it.  The drop has no effect until an implementation of notifyDrop is provided.
23501  * @constructor
23502  * @param {String/HTMLElement/Element} el The container element
23503  * @param {Object} config
23504  */
23505 Roo.dd.DropTarget = function(el, config){
23506     this.el = Roo.get(el);
23507     
23508     var listeners = false; ;
23509     if (config && config.listeners) {
23510         listeners= config.listeners;
23511         delete config.listeners;
23512     }
23513     Roo.apply(this, config);
23514     
23515     if(this.containerScroll){
23516         Roo.dd.ScrollManager.register(this.el);
23517     }
23518     this.addEvents( {
23519          /**
23520          * @scope Roo.dd.DropTarget
23521          */
23522          
23523          /**
23524          * @event enter
23525          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
23526          * target.  This default implementation adds the CSS class specified by overClass (if any) to the drop element
23527          * and returns the dropAllowed config value.  This method should be overridden if drop validation is required.
23528          * 
23529          * IMPORTANT : it should set  this.valid to true|false
23530          * 
23531          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23532          * @param {Event} e The event
23533          * @param {Object} data An object containing arbitrary data supplied by the drag source
23534          */
23535         "enter" : true,
23536         
23537          /**
23538          * @event over
23539          * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
23540          * This method will be called on every mouse movement while the drag source is over the drop target.
23541          * This default implementation simply returns the dropAllowed config value.
23542          * 
23543          * IMPORTANT : it should set  this.valid to true|false
23544          * 
23545          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23546          * @param {Event} e The event
23547          * @param {Object} data An object containing arbitrary data supplied by the drag source
23548          
23549          */
23550         "over" : true,
23551         /**
23552          * @event out
23553          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
23554          * out of the target without dropping.  This default implementation simply removes the CSS class specified by
23555          * overClass (if any) from the drop element.
23556          * 
23557          * 
23558          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23559          * @param {Event} e The event
23560          * @param {Object} data An object containing arbitrary data supplied by the drag source
23561          */
23562          "out" : true,
23563          
23564         /**
23565          * @event drop
23566          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
23567          * been dropped on it.  This method has no default implementation and returns false, so you must provide an
23568          * implementation that does something to process the drop event and returns true so that the drag source's
23569          * repair action does not run.
23570          * 
23571          * IMPORTANT : it should set this.success
23572          * 
23573          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23574          * @param {Event} e The event
23575          * @param {Object} data An object containing arbitrary data supplied by the drag source
23576         */
23577          "drop" : true
23578     });
23579             
23580      
23581     Roo.dd.DropTarget.superclass.constructor.call(  this, 
23582         this.el.dom, 
23583         this.ddGroup || this.group,
23584         {
23585             isTarget: true,
23586             listeners : listeners || {} 
23587            
23588         
23589         }
23590     );
23591
23592 };
23593
23594 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
23595     /**
23596      * @cfg {String} overClass
23597      * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
23598      */
23599      /**
23600      * @cfg {String} ddGroup
23601      * The drag drop group to handle drop events for
23602      */
23603      
23604     /**
23605      * @cfg {String} dropAllowed
23606      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
23607      */
23608     dropAllowed : "x-dd-drop-ok",
23609     /**
23610      * @cfg {String} dropNotAllowed
23611      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
23612      */
23613     dropNotAllowed : "x-dd-drop-nodrop",
23614     /**
23615      * @cfg {boolean} success
23616      * set this after drop listener.. 
23617      */
23618     success : false,
23619     /**
23620      * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
23621      * if the drop point is valid for over/enter..
23622      */
23623     valid : false,
23624     // private
23625     isTarget : true,
23626
23627     // private
23628     isNotifyTarget : true,
23629     
23630     /**
23631      * @hide
23632      */
23633     notifyEnter : function(dd, e, data)
23634     {
23635         this.valid = true;
23636         this.fireEvent('enter', dd, e, data);
23637         if(this.overClass){
23638             this.el.addClass(this.overClass);
23639         }
23640         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
23641             this.valid ? this.dropAllowed : this.dropNotAllowed
23642         );
23643     },
23644
23645     /**
23646      * @hide
23647      */
23648     notifyOver : function(dd, e, data)
23649     {
23650         this.valid = true;
23651         this.fireEvent('over', dd, e, data);
23652         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
23653             this.valid ? this.dropAllowed : this.dropNotAllowed
23654         );
23655     },
23656
23657     /**
23658      * @hide
23659      */
23660     notifyOut : function(dd, e, data)
23661     {
23662         this.fireEvent('out', dd, e, data);
23663         if(this.overClass){
23664             this.el.removeClass(this.overClass);
23665         }
23666     },
23667
23668     /**
23669      * @hide
23670      */
23671     notifyDrop : function(dd, e, data)
23672     {
23673         this.success = false;
23674         this.fireEvent('drop', dd, e, data);
23675         return this.success;
23676     }
23677 });/*
23678  * Based on:
23679  * Ext JS Library 1.1.1
23680  * Copyright(c) 2006-2007, Ext JS, LLC.
23681  *
23682  * Originally Released Under LGPL - original licence link has changed is not relivant.
23683  *
23684  * Fork - LGPL
23685  * <script type="text/javascript">
23686  */
23687
23688
23689 /**
23690  * @class Roo.dd.DragZone
23691  * @extends Roo.dd.DragSource
23692  * This class provides a container DD instance that proxies for multiple child node sources.<br />
23693  * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
23694  * @constructor
23695  * @param {String/HTMLElement/Element} el The container element
23696  * @param {Object} config
23697  */
23698 Roo.dd.DragZone = function(el, config){
23699     Roo.dd.DragZone.superclass.constructor.call(this, el, config);
23700     if(this.containerScroll){
23701         Roo.dd.ScrollManager.register(this.el);
23702     }
23703 };
23704
23705 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
23706     /**
23707      * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
23708      * for auto scrolling during drag operations.
23709      */
23710     /**
23711      * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
23712      * method after a failed drop (defaults to "c3daf9" - light blue)
23713      */
23714
23715     /**
23716      * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
23717      * for a valid target to drag based on the mouse down. Override this method
23718      * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
23719      * object has a "ddel" attribute (with an HTML Element) for other functions to work.
23720      * @param {EventObject} e The mouse down event
23721      * @return {Object} The dragData
23722      */
23723     getDragData : function(e){
23724         return Roo.dd.Registry.getHandleFromEvent(e);
23725     },
23726     
23727     /**
23728      * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
23729      * this.dragData.ddel
23730      * @param {Number} x The x position of the click on the dragged object
23731      * @param {Number} y The y position of the click on the dragged object
23732      * @return {Boolean} true to continue the drag, false to cancel
23733      */
23734     onInitDrag : function(x, y){
23735         this.proxy.update(this.dragData.ddel.cloneNode(true));
23736         this.onStartDrag(x, y);
23737         return true;
23738     },
23739     
23740     /**
23741      * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel 
23742      */
23743     afterRepair : function(){
23744         if(Roo.enableFx){
23745             Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
23746         }
23747         this.dragging = false;
23748     },
23749
23750     /**
23751      * Called before a repair of an invalid drop to get the XY to animate to. By default returns
23752      * the XY of this.dragData.ddel
23753      * @param {EventObject} e The mouse up event
23754      * @return {Array} The xy location (e.g. [100, 200])
23755      */
23756     getRepairXY : function(e){
23757         return Roo.Element.fly(this.dragData.ddel).getXY();  
23758     }
23759 });/*
23760  * Based on:
23761  * Ext JS Library 1.1.1
23762  * Copyright(c) 2006-2007, Ext JS, LLC.
23763  *
23764  * Originally Released Under LGPL - original licence link has changed is not relivant.
23765  *
23766  * Fork - LGPL
23767  * <script type="text/javascript">
23768  */
23769 /**
23770  * @class Roo.dd.DropZone
23771  * @extends Roo.dd.DropTarget
23772  * This class provides a container DD instance that proxies for multiple child node targets.<br />
23773  * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
23774  * @constructor
23775  * @param {String/HTMLElement/Element} el The container element
23776  * @param {Object} config
23777  */
23778 Roo.dd.DropZone = function(el, config){
23779     Roo.dd.DropZone.superclass.constructor.call(this, el, config);
23780 };
23781
23782 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
23783     /**
23784      * Returns a custom data object associated with the DOM node that is the target of the event.  By default
23785      * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
23786      * provide your own custom lookup.
23787      * @param {Event} e The event
23788      * @return {Object} data The custom data
23789      */
23790     getTargetFromEvent : function(e){
23791         return Roo.dd.Registry.getTargetFromEvent(e);
23792     },
23793
23794     /**
23795      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
23796      * that it has registered.  This method has no default implementation and should be overridden to provide
23797      * node-specific processing if necessary.
23798      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from 
23799      * {@link #getTargetFromEvent} for this node)
23800      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23801      * @param {Event} e The event
23802      * @param {Object} data An object containing arbitrary data supplied by the drag source
23803      */
23804     onNodeEnter : function(n, dd, e, data){
23805         
23806     },
23807
23808     /**
23809      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
23810      * that it has registered.  The default implementation returns this.dropNotAllowed, so it should be
23811      * overridden to provide the proper feedback.
23812      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
23813      * {@link #getTargetFromEvent} for this node)
23814      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23815      * @param {Event} e The event
23816      * @param {Object} data An object containing arbitrary data supplied by the drag source
23817      * @return {String} status The CSS class that communicates the drop status back to the source so that the
23818      * underlying {@link Roo.dd.StatusProxy} can be updated
23819      */
23820     onNodeOver : function(n, dd, e, data){
23821         return this.dropAllowed;
23822     },
23823
23824     /**
23825      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
23826      * the drop node without dropping.  This method has no default implementation and should be overridden to provide
23827      * node-specific processing if necessary.
23828      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
23829      * {@link #getTargetFromEvent} for this node)
23830      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23831      * @param {Event} e The event
23832      * @param {Object} data An object containing arbitrary data supplied by the drag source
23833      */
23834     onNodeOut : function(n, dd, e, data){
23835         
23836     },
23837
23838     /**
23839      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
23840      * the drop node.  The default implementation returns false, so it should be overridden to provide the
23841      * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
23842      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
23843      * {@link #getTargetFromEvent} for this node)
23844      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23845      * @param {Event} e The event
23846      * @param {Object} data An object containing arbitrary data supplied by the drag source
23847      * @return {Boolean} True if the drop was valid, else false
23848      */
23849     onNodeDrop : function(n, dd, e, data){
23850         return false;
23851     },
23852
23853     /**
23854      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
23855      * but not over any of its registered drop nodes.  The default implementation returns this.dropNotAllowed, so
23856      * it should be overridden to provide the proper feedback if necessary.
23857      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23858      * @param {Event} e The event
23859      * @param {Object} data An object containing arbitrary data supplied by the drag source
23860      * @return {String} status The CSS class that communicates the drop status back to the source so that the
23861      * underlying {@link Roo.dd.StatusProxy} can be updated
23862      */
23863     onContainerOver : function(dd, e, data){
23864         return this.dropNotAllowed;
23865     },
23866
23867     /**
23868      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
23869      * but not on any of its registered drop nodes.  The default implementation returns false, so it should be
23870      * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
23871      * be able to accept drops.  It should return true when valid so that the drag source's repair action does not run.
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     onContainerDrop : function(dd, e, data){
23878         return false;
23879     },
23880
23881     /**
23882      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
23883      * the zone.  The default implementation returns this.dropNotAllowed and expects that only registered drop
23884      * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
23885      * you should override this method and provide a custom implementation.
23886      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23887      * @param {Event} e The event
23888      * @param {Object} data An object containing arbitrary data supplied by the drag source
23889      * @return {String} status The CSS class that communicates the drop status back to the source so that the
23890      * underlying {@link Roo.dd.StatusProxy} can be updated
23891      */
23892     notifyEnter : function(dd, e, data){
23893         return this.dropNotAllowed;
23894     },
23895
23896     /**
23897      * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
23898      * This method will be called on every mouse movement while the drag source is over the drop zone.
23899      * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
23900      * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
23901      * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
23902      * registered node, it will call {@link #onContainerOver}.
23903      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23904      * @param {Event} e The event
23905      * @param {Object} data An object containing arbitrary data supplied by the drag source
23906      * @return {String} status The CSS class that communicates the drop status back to the source so that the
23907      * underlying {@link Roo.dd.StatusProxy} can be updated
23908      */
23909     notifyOver : function(dd, e, data){
23910         var n = this.getTargetFromEvent(e);
23911         if(!n){ // not over valid drop target
23912             if(this.lastOverNode){
23913                 this.onNodeOut(this.lastOverNode, dd, e, data);
23914                 this.lastOverNode = null;
23915             }
23916             return this.onContainerOver(dd, e, data);
23917         }
23918         if(this.lastOverNode != n){
23919             if(this.lastOverNode){
23920                 this.onNodeOut(this.lastOverNode, dd, e, data);
23921             }
23922             this.onNodeEnter(n, dd, e, data);
23923             this.lastOverNode = n;
23924         }
23925         return this.onNodeOver(n, dd, e, data);
23926     },
23927
23928     /**
23929      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
23930      * out of the zone without dropping.  If the drag source is currently over a registered node, the notification
23931      * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
23932      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23933      * @param {Event} e The event
23934      * @param {Object} data An object containing arbitrary data supplied by the drag zone
23935      */
23936     notifyOut : function(dd, e, data){
23937         if(this.lastOverNode){
23938             this.onNodeOut(this.lastOverNode, dd, e, data);
23939             this.lastOverNode = null;
23940         }
23941     },
23942
23943     /**
23944      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
23945      * been dropped on it.  The drag zone will look up the target node based on the event passed in, and if there
23946      * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
23947      * otherwise it will call {@link #onContainerDrop}.
23948      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23949      * @param {Event} e The event
23950      * @param {Object} data An object containing arbitrary data supplied by the drag source
23951      * @return {Boolean} True if the drop was valid, else false
23952      */
23953     notifyDrop : function(dd, e, data){
23954         if(this.lastOverNode){
23955             this.onNodeOut(this.lastOverNode, dd, e, data);
23956             this.lastOverNode = null;
23957         }
23958         var n = this.getTargetFromEvent(e);
23959         return n ?
23960             this.onNodeDrop(n, dd, e, data) :
23961             this.onContainerDrop(dd, e, data);
23962     },
23963
23964     // private
23965     triggerCacheRefresh : function(){
23966         Roo.dd.DDM.refreshCache(this.groups);
23967     }  
23968 });