Date.js
[roojs1] / roojs-core-debug.js
1 /*
2  * Based on:
3  * Ext JS Library 1.1.1
4  * Copyright(c) 2006-2007, Ext JS, LLC.
5  *
6  * Originally Released Under LGPL - original licence link has changed is not relivant.
7  *
8  * Fork - LGPL
9  * <script type="text/javascript">
10  */
11  
12
13
14
15
16 // for old browsers
17 window["undefined"] = window["undefined"];
18
19 /**
20  * @class Roo
21  * Roo core utilities and functions.
22  * @static
23  */
24 var Roo = {}; 
25 /**
26  * Copies all the properties of config to obj.
27  * @param {Object} obj The receiver of the properties
28  * @param {Object} config The source of the properties
29  * @param {Object} defaults A different object that will also be applied for default values
30  * @return {Object} returns obj
31  * @member Roo apply
32  */
33
34  
35 Roo.apply = function(o, c, defaults){
36     if(defaults){
37         // no "this" reference for friendly out of scope calls
38         Roo.apply(o, defaults);
39     }
40     if(o && c && typeof c == 'object'){
41         for(var p in c){
42             o[p] = c[p];
43         }
44     }
45     return o;
46 };
47
48
49 (function(){
50     var idSeed = 0;
51     var ua = navigator.userAgent.toLowerCase();
52
53     var isStrict = document.compatMode == "CSS1Compat",
54         isOpera = ua.indexOf("opera") > -1,
55         isSafari = (/webkit|khtml/).test(ua),
56         isFirefox = ua.indexOf("firefox") > -1,
57         isIE = ua.indexOf("msie") > -1,
58         isIE7 = ua.indexOf("msie 7") > -1,
59         isIE11 = /trident.*rv\:11\./.test(ua),
60         isEdge = ua.indexOf("edge") > -1,
61         isGecko = !isSafari && ua.indexOf("gecko") > -1,
62         isBorderBox = isIE && !isStrict,
63         isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
64         isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
65         isLinux = (ua.indexOf("linux") != -1),
66         isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
67         isIOS = /iphone|ipad/.test(ua),
68         isAndroid = /android/.test(ua),
69         isTouch =  (function() {
70             try {
71                 if (ua.indexOf('chrome') != -1 && ua.indexOf('android') == -1) {
72                     window.addEventListener('touchstart', function __set_has_touch__ () {
73                         Roo.isTouch = true;
74                         window.removeEventListener('touchstart', __set_has_touch__);
75                     });
76                     return false; // no touch on chrome!?
77                 }
78                 document.createEvent("TouchEvent");  
79                 return true;  
80             } catch (e) {  
81                 return false;  
82             } 
83             
84         })();
85     // remove css image flicker
86         if(isIE && !isIE7){
87         try{
88             document.execCommand("BackgroundImageCache", false, true);
89         }catch(e){}
90     }
91     
92     Roo.apply(Roo, {
93         /**
94          * True if the browser is in strict mode
95          * @type Boolean
96          */
97         isStrict : isStrict,
98         /**
99          * True if the page is running over SSL
100          * @type Boolean
101          */
102         isSecure : isSecure,
103         /**
104          * True when the document is fully initialized and ready for action
105          * @type Boolean
106          */
107         isReady : false,
108         /**
109          * Turn on debugging output (currently only the factory uses this)
110          * @type Boolean
111          */
112         
113         debug: false,
114
115         /**
116          * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
117          * @type Boolean
118          */
119         enableGarbageCollector : true,
120
121         /**
122          * True to automatically purge event listeners after uncaching an element (defaults to false).
123          * Note: this only happens if enableGarbageCollector is true.
124          * @type Boolean
125          */
126         enableListenerCollection:false,
127
128         /**
129          * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
130          * the IE insecure content warning (defaults to javascript:false).
131          * @type String
132          */
133         SSL_SECURE_URL : "javascript:false",
134
135         /**
136          * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
137          * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
138          * @type String
139          */
140         BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
141
142         emptyFn : function(){},
143         
144         /**
145          * Copies all the properties of config to obj if they don't already exist.
146          * @param {Object} obj The receiver of the properties
147          * @param {Object} config The source of the properties
148          * @return {Object} returns obj
149          */
150         applyIf : function(o, c){
151             if(o && c){
152                 for(var p in c){
153                     if(typeof o[p] == "undefined"){ o[p] = c[p]; }
154                 }
155             }
156             return o;
157         },
158
159         /**
160          * Applies event listeners to elements by selectors when the document is ready.
161          * The event name is specified with an @ suffix.
162 <pre><code>
163 Roo.addBehaviors({
164    // add a listener for click on all anchors in element with id foo
165    '#foo a@click' : function(e, t){
166        // do something
167    },
168
169    // add the same listener to multiple selectors (separated by comma BEFORE the @)
170    '#foo a, #bar span.some-class@mouseover' : function(){
171        // do something
172    }
173 });
174 </code></pre>
175          * @param {Object} obj The list of behaviors to apply
176          */
177         addBehaviors : function(o){
178             if(!Roo.isReady){
179                 Roo.onReady(function(){
180                     Roo.addBehaviors(o);
181                 });
182                 return;
183             }
184             var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
185             for(var b in o){
186                 var parts = b.split('@');
187                 if(parts[1]){ // for Object prototype breakers
188                     var s = parts[0];
189                     if(!cache[s]){
190                         cache[s] = Roo.select(s);
191                     }
192                     cache[s].on(parts[1], o[b]);
193                 }
194             }
195             cache = null;
196         },
197
198         /**
199          * Generates unique ids. If the element already has an id, it is unchanged
200          * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
201          * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
202          * @return {String} The generated Id.
203          */
204         id : function(el, prefix){
205             prefix = prefix || "roo-gen";
206             el = Roo.getDom(el);
207             var id = prefix + (++idSeed);
208             return el ? (el.id ? el.id : (el.id = id)) : id;
209         },
210          
211        
212         /**
213          * Extends one class with another class and optionally overrides members with the passed literal. This class
214          * also adds the function "override()" to the class that can be used to override
215          * members on an instance.
216          * @param {Object} subclass The class inheriting the functionality
217          * @param {Object} superclass The class being extended
218          * @param {Object} overrides (optional) A literal with members
219          * @method extend
220          */
221         extend : function(){
222             // inline overrides
223             var io = function(o){
224                 for(var m in o){
225                     this[m] = o[m];
226                 }
227             };
228             return function(sb, sp, overrides){
229                 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
230                     overrides = sp;
231                     sp = sb;
232                     sb = function(){sp.apply(this, arguments);};
233                 }
234                 var F = function(){}, sbp, spp = sp.prototype;
235                 F.prototype = spp;
236                 sbp = sb.prototype = new F();
237                 sbp.constructor=sb;
238                 sb.superclass=spp;
239                 
240                 if(spp.constructor == Object.prototype.constructor){
241                     spp.constructor=sp;
242                    
243                 }
244                 
245                 sb.override = function(o){
246                     Roo.override(sb, o);
247                 };
248                 sbp.override = io;
249                 Roo.override(sb, overrides);
250                 return sb;
251             };
252         }(),
253
254         /**
255          * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
256          * Usage:<pre><code>
257 Roo.override(MyClass, {
258     newMethod1: function(){
259         // etc.
260     },
261     newMethod2: function(foo){
262         // etc.
263     }
264 });
265  </code></pre>
266          * @param {Object} origclass The class to override
267          * @param {Object} overrides The list of functions to add to origClass.  This should be specified as an object literal
268          * containing one or more methods.
269          * @method override
270          */
271         override : function(origclass, overrides){
272             if(overrides){
273                 var p = origclass.prototype;
274                 for(var method in overrides){
275                     p[method] = overrides[method];
276                 }
277             }
278         },
279         /**
280          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
281          * <pre><code>
282 Roo.namespace('Company', 'Company.data');
283 Company.Widget = function() { ... }
284 Company.data.CustomStore = function(config) { ... }
285 </code></pre>
286          * @param {String} namespace1
287          * @param {String} namespace2
288          * @param {String} etc
289          * @method namespace
290          */
291         namespace : function(){
292             var a=arguments, o=null, i, j, d, rt;
293             for (i=0; i<a.length; ++i) {
294                 d=a[i].split(".");
295                 rt = d[0];
296                 /** eval:var:o */
297                 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
298                 for (j=1; j<d.length; ++j) {
299                     o[d[j]]=o[d[j]] || {};
300                     o=o[d[j]];
301                 }
302             }
303         },
304         /**
305          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
306          * <pre><code>
307 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
308 Roo.factory(conf, Roo.data);
309 </code></pre>
310          * @param {String} classname
311          * @param {String} namespace (optional)
312          * @method factory
313          */
314          
315         factory : function(c, ns)
316         {
317             // no xtype, no ns or c.xns - or forced off by c.xns
318             if (!c.xtype   || (!ns && !c.xns) ||  (c.xns === false)) { // not enough info...
319                 return c;
320             }
321             ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
322             if (c.constructor == ns[c.xtype]) {// already created...
323                 return c;
324             }
325             if (ns[c.xtype]) {
326                 if (Roo.debug) { Roo.log("Roo.Factory(" + c.xtype + ")"); }
327                 var ret = new ns[c.xtype](c);
328                 ret.xns = false;
329                 return ret;
330             }
331             c.xns = false; // prevent recursion..
332             return c;
333         },
334          /**
335          * Logs to console if it can.
336          *
337          * @param {String|Object} string
338          * @method log
339          */
340         log : function(s)
341         {
342             if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
343                 return; // alerT?
344             }
345             
346             console.log(s);
347         },
348         /**
349          * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2".  Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
350          * @param {Object} o
351          * @return {String}
352          */
353         urlEncode : function(o){
354             if(!o){
355                 return "";
356             }
357             var buf = [];
358             for(var key in o){
359                 var ov = o[key], k = Roo.encodeURIComponent(key);
360                 var type = typeof ov;
361                 if(type == 'undefined'){
362                     buf.push(k, "=&");
363                 }else if(type != "function" && type != "object"){
364                     buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
365                 }else if(ov instanceof Array){
366                     if (ov.length) {
367                             for(var i = 0, len = ov.length; i < len; i++) {
368                                 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
369                             }
370                         } else {
371                             buf.push(k, "=&");
372                         }
373                 }
374             }
375             buf.pop();
376             return buf.join("");
377         },
378          /**
379          * Safe version of encodeURIComponent
380          * @param {String} data 
381          * @return {String} 
382          */
383         
384         encodeURIComponent : function (data)
385         {
386             try {
387                 return encodeURIComponent(data);
388             } catch(e) {} // should be an uri encode error.
389             
390             if (data == '' || data == null){
391                return '';
392             }
393             // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
394             function nibble_to_hex(nibble){
395                 var chars = '0123456789ABCDEF';
396                 return chars.charAt(nibble);
397             }
398             data = data.toString();
399             var buffer = '';
400             for(var i=0; i<data.length; i++){
401                 var c = data.charCodeAt(i);
402                 var bs = new Array();
403                 if (c > 0x10000){
404                         // 4 bytes
405                     bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
406                     bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
407                     bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
408                     bs[3] = 0x80 | (c & 0x3F);
409                 }else if (c > 0x800){
410                          // 3 bytes
411                     bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
412                     bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
413                     bs[2] = 0x80 | (c & 0x3F);
414                 }else if (c > 0x80){
415                        // 2 bytes
416                     bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
417                     bs[1] = 0x80 | (c & 0x3F);
418                 }else{
419                         // 1 byte
420                     bs[0] = c;
421                 }
422                 for(var j=0; j<bs.length; j++){
423                     var b = bs[j];
424                     var hex = nibble_to_hex((b & 0xF0) >>> 4) 
425                             + nibble_to_hex(b &0x0F);
426                     buffer += '%'+hex;
427                }
428             }
429             return buffer;    
430              
431         },
432
433         /**
434          * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
435          * @param {String} string
436          * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
437          * @return {Object} A literal with members
438          */
439         urlDecode : function(string, overwrite){
440             if(!string || !string.length){
441                 return {};
442             }
443             var obj = {};
444             var pairs = string.split('&');
445             var pair, name, value;
446             for(var i = 0, len = pairs.length; i < len; i++){
447                 pair = pairs[i].split('=');
448                 name = decodeURIComponent(pair[0]);
449                 value = decodeURIComponent(pair[1]);
450                 if(overwrite !== true){
451                     if(typeof obj[name] == "undefined"){
452                         obj[name] = value;
453                     }else if(typeof obj[name] == "string"){
454                         obj[name] = [obj[name]];
455                         obj[name].push(value);
456                     }else{
457                         obj[name].push(value);
458                     }
459                 }else{
460                     obj[name] = value;
461                 }
462             }
463             return obj;
464         },
465
466         /**
467          * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
468          * passed array is not really an array, your function is called once with it.
469          * The supplied function is called with (Object item, Number index, Array allItems).
470          * @param {Array/NodeList/Mixed} array
471          * @param {Function} fn
472          * @param {Object} scope
473          */
474         each : function(array, fn, scope){
475             if(typeof array.length == "undefined" || typeof array == "string"){
476                 array = [array];
477             }
478             for(var i = 0, len = array.length; i < len; i++){
479                 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
480             }
481         },
482
483         // deprecated
484         combine : function(){
485             var as = arguments, l = as.length, r = [];
486             for(var i = 0; i < l; i++){
487                 var a = as[i];
488                 if(a instanceof Array){
489                     r = r.concat(a);
490                 }else if(a.length !== undefined && !a.substr){
491                     r = r.concat(Array.prototype.slice.call(a, 0));
492                 }else{
493                     r.push(a);
494                 }
495             }
496             return r;
497         },
498
499         /**
500          * Escapes the passed string for use in a regular expression
501          * @param {String} str
502          * @return {String}
503          */
504         escapeRe : function(s) {
505             return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
506         },
507
508         // internal
509         callback : function(cb, scope, args, delay){
510             if(typeof cb == "function"){
511                 if(delay){
512                     cb.defer(delay, scope, args || []);
513                 }else{
514                     cb.apply(scope, args || []);
515                 }
516             }
517         },
518
519         /**
520          * Return the dom node for the passed string (id), dom node, or Roo.Element
521          * @param {String/HTMLElement/Roo.Element} el
522          * @return HTMLElement
523          */
524         getDom : function(el){
525             if(!el){
526                 return null;
527             }
528             return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
529         },
530
531         /**
532         * Shorthand for {@link Roo.ComponentMgr#get}
533         * @param {String} id
534         * @return Roo.Component
535         */
536         getCmp : function(id){
537             return Roo.ComponentMgr.get(id);
538         },
539          
540         num : function(v, defaultValue){
541             if(typeof v != 'number'){
542                 return defaultValue;
543             }
544             return v;
545         },
546
547         destroy : function(){
548             for(var i = 0, a = arguments, len = a.length; i < len; i++) {
549                 var as = a[i];
550                 if(as){
551                     if(as.dom){
552                         as.removeAllListeners();
553                         as.remove();
554                         continue;
555                     }
556                     if(typeof as.purgeListeners == 'function'){
557                         as.purgeListeners();
558                     }
559                     if(typeof as.destroy == 'function'){
560                         as.destroy();
561                     }
562                 }
563             }
564         },
565
566         // inpired by a similar function in mootools library
567         /**
568          * Returns the type of object that is passed in. If the object passed in is null or undefined it
569          * return false otherwise it returns one of the following values:<ul>
570          * <li><b>string</b>: If the object passed is a string</li>
571          * <li><b>number</b>: If the object passed is a number</li>
572          * <li><b>boolean</b>: If the object passed is a boolean value</li>
573          * <li><b>function</b>: If the object passed is a function reference</li>
574          * <li><b>object</b>: If the object passed is an object</li>
575          * <li><b>array</b>: If the object passed is an array</li>
576          * <li><b>regexp</b>: If the object passed is a regular expression</li>
577          * <li><b>element</b>: If the object passed is a DOM Element</li>
578          * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
579          * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
580          * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
581          * @param {Mixed} object
582          * @return {String}
583          */
584         type : function(o){
585             if(o === undefined || o === null){
586                 return false;
587             }
588             if(o.htmlElement){
589                 return 'element';
590             }
591             var t = typeof o;
592             if(t == 'object' && o.nodeName) {
593                 switch(o.nodeType) {
594                     case 1: return 'element';
595                     case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
596                 }
597             }
598             if(t == 'object' || t == 'function') {
599                 switch(o.constructor) {
600                     case Array: return 'array';
601                     case RegExp: return 'regexp';
602                 }
603                 if(typeof o.length == 'number' && typeof o.item == 'function') {
604                     return 'nodelist';
605                 }
606             }
607             return t;
608         },
609
610         /**
611          * Returns true if the passed value is null, undefined or an empty string (optional).
612          * @param {Mixed} value The value to test
613          * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
614          * @return {Boolean}
615          */
616         isEmpty : function(v, allowBlank){
617             return v === null || v === undefined || (!allowBlank ? v === '' : false);
618         },
619         
620         /** @type Boolean */
621         isOpera : isOpera,
622         /** @type Boolean */
623         isSafari : isSafari,
624         /** @type Boolean */
625         isFirefox : isFirefox,
626         /** @type Boolean */
627         isIE : isIE,
628         /** @type Boolean */
629         isIE7 : isIE7,
630         /** @type Boolean */
631         isIE11 : isIE11,
632         /** @type Boolean */
633         isEdge : isEdge,
634         /** @type Boolean */
635         isGecko : isGecko,
636         /** @type Boolean */
637         isBorderBox : isBorderBox,
638         /** @type Boolean */
639         isWindows : isWindows,
640         /** @type Boolean */
641         isLinux : isLinux,
642         /** @type Boolean */
643         isMac : isMac,
644         /** @type Boolean */
645         isIOS : isIOS,
646         /** @type Boolean */
647         isAndroid : isAndroid,
648         /** @type Boolean */
649         isTouch : isTouch,
650
651         /**
652          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
653          * you may want to set this to true.
654          * @type Boolean
655          */
656         useShims : ((isIE && !isIE7) || (isGecko && isMac)),
657         
658         
659                 
660         /**
661          * Selects a single element as a Roo Element
662          * This is about as close as you can get to jQuery's $('do crazy stuff')
663          * @param {String} selector The selector/xpath query
664          * @param {Node} root (optional) The start of the query (defaults to document).
665          * @return {Roo.Element}
666          */
667         selectNode : function(selector, root) 
668         {
669             var node = Roo.DomQuery.selectNode(selector,root);
670             return node ? Roo.get(node) : new Roo.Element(false);
671         },
672                 /**
673                  * Find the current bootstrap width Grid size
674                  * Note xs is the default for smaller.. - this is currently used by grids to render correct columns
675                  * @returns {String} (xs|sm|md|lg|xl)
676                  */
677                 
678                 getGridSize : function()
679                 {
680                         var w = Roo.lib.Dom.getViewWidth();
681                         switch(true) {
682                                 case w > 1200:
683                                         return 'xl';
684                                 case w > 992:
685                                         return 'lg';
686                                 case w > 768:
687                                         return 'md';
688                                 case w > 576:
689                                         return 'sm';
690                                 default:
691                                         return 'xs'
692                         }
693                         
694                 }
695         
696     });
697
698
699 })();
700
701 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
702                 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
703                 "Roo.app", "Roo.ux" 
704                );
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); v.setFullYear(y);}\n"
1396         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1397         + "{v = new Date(y, m, d, h, i); v.setFullYear(y);}\n"
1398         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1399         + "{v = new Date(y, m, d, h); v.setFullYear(y);}\n"
1400         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1401         + "{v = new Date(y, m, d); v.setFullYear(y);}\n"
1402         + "else if (y >= 0 && m >= 0)\n"
1403         + "{v = new Date(y, m); v.setFullYear(y);}\n"
1404         + "else if (y >= 0)\n"
1405         + "{v = new Date(y); v.setFullYear(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 = Math.max(0,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         Roo.log(["UpdateNode" , from, to]);
5155         if (from.nodeType != to.nodeType) {
5156             Roo.log(["ReplaceChild - mismatch notType" , to, from ]);
5157             from.parentNode.replaceChild(to, from);
5158         }
5159         
5160         if (from.nodeType == 3) {
5161             // assume it's text?!
5162             if (from.data == to.data) {
5163                 return;
5164             }
5165             from.data = to.data;
5166             return;
5167         }
5168         
5169         // assume 'to' doesnt have '1/3 nodetypes!
5170         if (from.nodeType !=1 || from.tagName != to.tagName) {
5171             Roo.log(["ReplaceChild" , from, to ]);
5172             from.parentNode.replaceChild(to, from);
5173             return;
5174         }
5175         // compare attributes
5176         var ar = Array.from(from.attributes);
5177         for(var i = 0; i< ar.length;i++) {
5178             if (to.hasAttribute(ar[i].name)) {
5179                 continue;
5180             }
5181             if (ar[i].name == 'id') { // always keep ids?
5182                 continue;
5183             }
5184             from.removeAttribute(ar[i].name);
5185         }
5186         ar = to.attributes;
5187         for(var i = 0; i< ar.length;i++) {
5188             if (from.getAttribute(ar[i].name) == to.getAttribute(ar[i].name)) {
5189                 continue;
5190             }
5191             from.setAttribute(ar[i].name, to.getAttribute(ar[i].name));
5192         }
5193         // children
5194         var far = Array.from(from.childNodes);
5195         var tar = Array.from(to.childNodes);
5196         // if the lengths are different.. then it's probably a editable content change, rather than
5197         // a change of the block definition..
5198         
5199         // this did notwork , as our rebuilt nodes did not include ID's so did not match at all.
5200          /*if (from.innerHTML == to.innerHTML) {
5201             return;
5202         }
5203         if (far.length != tar.length) {
5204             from.innerHTML = to.innerHTML;
5205             return;
5206         }
5207         */
5208         
5209         for(var i = 0; i < Math.max(tar.length, far.length); i++) {
5210             if (i >= far.length) {
5211                 from.appendChild(tar[i]);
5212                 Roo.log(["add", tar[i]]);
5213                 
5214             } else if ( i  >= tar.length) {
5215                 from.removeChild(far[i]);
5216                 Roo.log(["remove", far[i]]);
5217             } else {
5218                 
5219                 updateNode(far[i], tar[i]);
5220             }    
5221         }
5222         
5223         
5224         
5225         
5226     };
5227     
5228     
5229
5230     return {
5231         /** True to force the use of DOM instead of html fragments @type Boolean */
5232         useDom : false,
5233     
5234         /**
5235          * Returns the markup for the passed Element(s) config
5236          * @param {Object} o The Dom object spec (and children)
5237          * @return {String}
5238          */
5239         markup : function(o){
5240             return createHtml(o);
5241         },
5242     
5243         /**
5244          * Applies a style specification to an element
5245          * @param {String/HTMLElement} el The element to apply styles to
5246          * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
5247          * a function which returns such a specification.
5248          */
5249         applyStyles : function(el, styles){
5250             if(styles){
5251                el = Roo.fly(el);
5252                if(typeof styles == "string"){
5253                    var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
5254                    var matches;
5255                    while ((matches = re.exec(styles)) != null){
5256                        el.setStyle(matches[1], matches[2]);
5257                    }
5258                }else if (typeof styles == "object"){
5259                    for (var style in styles){
5260                       el.setStyle(style, styles[style]);
5261                    }
5262                }else if (typeof styles == "function"){
5263                     Roo.DomHelper.applyStyles(el, styles.call());
5264                }
5265             }
5266         },
5267     
5268         /**
5269          * Inserts an HTML fragment into the Dom
5270          * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
5271          * @param {HTMLElement} el The context element
5272          * @param {String} html The HTML fragmenet
5273          * @return {HTMLElement} The new node
5274          */
5275         insertHtml : function(where, el, html){
5276             where = where.toLowerCase();
5277             if(el.insertAdjacentHTML){
5278                 if(tableRe.test(el.tagName)){
5279                     var rs;
5280                     if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
5281                         return rs;
5282                     }
5283                 }
5284                 switch(where){
5285                     case "beforebegin":
5286                         el.insertAdjacentHTML('BeforeBegin', html);
5287                         return el.previousSibling;
5288                     case "afterbegin":
5289                         el.insertAdjacentHTML('AfterBegin', html);
5290                         return el.firstChild;
5291                     case "beforeend":
5292                         el.insertAdjacentHTML('BeforeEnd', html);
5293                         return el.lastChild;
5294                     case "afterend":
5295                         el.insertAdjacentHTML('AfterEnd', html);
5296                         return el.nextSibling;
5297                 }
5298                 throw 'Illegal insertion point -> "' + where + '"';
5299             }
5300             var range = el.ownerDocument.createRange();
5301             var frag;
5302             switch(where){
5303                  case "beforebegin":
5304                     range.setStartBefore(el);
5305                     frag = range.createContextualFragment(html);
5306                     el.parentNode.insertBefore(frag, el);
5307                     return el.previousSibling;
5308                  case "afterbegin":
5309                     if(el.firstChild){
5310                         range.setStartBefore(el.firstChild);
5311                         frag = range.createContextualFragment(html);
5312                         el.insertBefore(frag, el.firstChild);
5313                         return el.firstChild;
5314                     }else{
5315                         el.innerHTML = html;
5316                         return el.firstChild;
5317                     }
5318                 case "beforeend":
5319                     if(el.lastChild){
5320                         range.setStartAfter(el.lastChild);
5321                         frag = range.createContextualFragment(html);
5322                         el.appendChild(frag);
5323                         return el.lastChild;
5324                     }else{
5325                         el.innerHTML = html;
5326                         return el.lastChild;
5327                     }
5328                 case "afterend":
5329                     range.setStartAfter(el);
5330                     frag = range.createContextualFragment(html);
5331                     el.parentNode.insertBefore(frag, el.nextSibling);
5332                     return el.nextSibling;
5333                 }
5334                 throw 'Illegal insertion point -> "' + where + '"';
5335         },
5336     
5337         /**
5338          * Creates new Dom element(s) and inserts them before el
5339          * @param {String/HTMLElement/Element} el The context element
5340          * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5341          * @param {Boolean} returnElement (optional) true to return a Roo.Element
5342          * @return {HTMLElement/Roo.Element} The new node
5343          */
5344         insertBefore : function(el, o, returnElement){
5345             return this.doInsert(el, o, returnElement, "beforeBegin");
5346         },
5347     
5348         /**
5349          * Creates new Dom element(s) and inserts them after el
5350          * @param {String/HTMLElement/Element} el The context element
5351          * @param {Object} o The Dom object spec (and children)
5352          * @param {Boolean} returnElement (optional) true to return a Roo.Element
5353          * @return {HTMLElement/Roo.Element} The new node
5354          */
5355         insertAfter : function(el, o, returnElement){
5356             return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
5357         },
5358     
5359         /**
5360          * Creates new Dom element(s) and inserts them as the first child of el
5361          * @param {String/HTMLElement/Element} el The context element
5362          * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5363          * @param {Boolean} returnElement (optional) true to return a Roo.Element
5364          * @return {HTMLElement/Roo.Element} The new node
5365          */
5366         insertFirst : function(el, o, returnElement){
5367             return this.doInsert(el, o, returnElement, "afterBegin");
5368         },
5369     
5370         // private
5371         doInsert : function(el, o, returnElement, pos, sibling){
5372             el = Roo.getDom(el);
5373             var newNode;
5374             if(this.useDom || o.ns){
5375                 newNode = createDom(o, null);
5376                 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
5377             }else{
5378                 var html = createHtml(o);
5379                 newNode = this.insertHtml(pos, el, html);
5380             }
5381             return returnElement ? Roo.get(newNode, true) : newNode;
5382         },
5383     
5384         /**
5385          * Creates new Dom element(s) and appends them to el
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         append : function(el, o, returnElement){
5392             el = Roo.getDom(el);
5393             var newNode;
5394             if(this.useDom || o.ns){
5395                 newNode = createDom(o, null);
5396                 el.appendChild(newNode);
5397             }else{
5398                 var html = createHtml(o);
5399                 newNode = this.insertHtml("beforeEnd", el, html);
5400             }
5401             return returnElement ? Roo.get(newNode, true) : newNode;
5402         },
5403     
5404         /**
5405          * Creates new Dom element(s) and overwrites the contents of el with them
5406          * @param {String/HTMLElement/Element} el The context element
5407          * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5408          * @param {Boolean} returnElement (optional) true to return a Roo.Element
5409          * @return {HTMLElement/Roo.Element} The new node
5410          */
5411         overwrite : function(el, o, returnElement)
5412         {
5413             el = Roo.getDom(el);
5414             if (o.ns) {
5415               
5416                 while (el.childNodes.length) {
5417                     el.removeChild(el.firstChild);
5418                 }
5419                 createDom(o, el);
5420             } else {
5421                 el.innerHTML = createHtml(o);   
5422             }
5423             
5424             return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
5425         },
5426     
5427         /**
5428          * Creates a new Roo.DomHelper.Template from the Dom object spec
5429          * @param {Object} o The Dom object spec (and children)
5430          * @return {Roo.DomHelper.Template} The new template
5431          */
5432         createTemplate : function(o){
5433             var html = createHtml(o);
5434             return new Roo.Template(html);
5435         },
5436          /**
5437          * Updates the first element with the spec from the o (replacing if necessary)
5438          * This iterates through the children, and updates attributes / children etc..
5439          * @param {String/HTMLElement/Element} el The context element
5440          * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5441          */
5442         
5443         update : function(el, o)
5444         {
5445             updateNode(Roo.getDom(el), createDom(o));
5446             
5447         }
5448         
5449         
5450     };
5451 }();
5452 /*
5453  * Based on:
5454  * Ext JS Library 1.1.1
5455  * Copyright(c) 2006-2007, Ext JS, LLC.
5456  *
5457  * Originally Released Under LGPL - original licence link has changed is not relivant.
5458  *
5459  * Fork - LGPL
5460  * <script type="text/javascript">
5461  */
5462  
5463 /**
5464 * @class Roo.Template
5465 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
5466 * For a list of available format functions, see {@link Roo.util.Format}.<br />
5467 * Usage:
5468 <pre><code>
5469 var t = new Roo.Template({
5470     html :  '&lt;div name="{id}"&gt;' + 
5471         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
5472         '&lt;/div&gt;',
5473     myformat: function (value, allValues) {
5474         return 'XX' + value;
5475     }
5476 });
5477 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
5478 </code></pre>
5479 * For more information see this blog post with examples:
5480 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
5481      - Create Elements using DOM, HTML fragments and Templates</a>. 
5482 * @constructor
5483 * @param {Object} cfg - Configuration object.
5484 */
5485 Roo.Template = function(cfg){
5486     // BC!
5487     if(cfg instanceof Array){
5488         cfg = cfg.join("");
5489     }else if(arguments.length > 1){
5490         cfg = Array.prototype.join.call(arguments, "");
5491     }
5492     
5493     
5494     if (typeof(cfg) == 'object') {
5495         Roo.apply(this,cfg)
5496     } else {
5497         // bc
5498         this.html = cfg;
5499     }
5500     if (this.url) {
5501         this.load();
5502     }
5503     
5504 };
5505 Roo.Template.prototype = {
5506     
5507     /**
5508      * @cfg {Function} onLoad Called after the template has been loaded and complied (usually from a remove source)
5509      */
5510     onLoad : false,
5511     
5512     
5513     /**
5514      * @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..
5515      *                    it should be fixed so that template is observable...
5516      */
5517     url : false,
5518     /**
5519      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
5520      */
5521     html : '',
5522     
5523     
5524     compiled : false,
5525     loaded : false,
5526     /**
5527      * Returns an HTML fragment of this template with the specified values applied.
5528      * @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'})
5529      * @return {String} The HTML fragment
5530      */
5531     
5532    
5533     
5534     applyTemplate : function(values){
5535         //Roo.log(["applyTemplate", values]);
5536         try {
5537            
5538             if(this.compiled){
5539                 return this.compiled(values);
5540             }
5541             var useF = this.disableFormats !== true;
5542             var fm = Roo.util.Format, tpl = this;
5543             var fn = function(m, name, format, args){
5544                 if(format && useF){
5545                     if(format.substr(0, 5) == "this."){
5546                         return tpl.call(format.substr(5), values[name], values);
5547                     }else{
5548                         if(args){
5549                             // quoted values are required for strings in compiled templates, 
5550                             // but for non compiled we need to strip them
5551                             // quoted reversed for jsmin
5552                             var re = /^\s*['"](.*)["']\s*$/;
5553                             args = args.split(',');
5554                             for(var i = 0, len = args.length; i < len; i++){
5555                                 args[i] = args[i].replace(re, "$1");
5556                             }
5557                             args = [values[name]].concat(args);
5558                         }else{
5559                             args = [values[name]];
5560                         }
5561                         return fm[format].apply(fm, args);
5562                     }
5563                 }else{
5564                     return values[name] !== undefined ? values[name] : "";
5565                 }
5566             };
5567             return this.html.replace(this.re, fn);
5568         } catch (e) {
5569             Roo.log(e);
5570             throw e;
5571         }
5572          
5573     },
5574     
5575     loading : false,
5576       
5577     load : function ()
5578     {
5579          
5580         if (this.loading) {
5581             return;
5582         }
5583         var _t = this;
5584         
5585         this.loading = true;
5586         this.compiled = false;
5587         
5588         var cx = new Roo.data.Connection();
5589         cx.request({
5590             url : this.url,
5591             method : 'GET',
5592             success : function (response) {
5593                 _t.loading = false;
5594                 _t.url = false;
5595                 
5596                 _t.set(response.responseText,true);
5597                 _t.loaded = true;
5598                 if (_t.onLoad) {
5599                     _t.onLoad();
5600                 }
5601              },
5602             failure : function(response) {
5603                 Roo.log("Template failed to load from " + _t.url);
5604                 _t.loading = false;
5605             }
5606         });
5607     },
5608
5609     /**
5610      * Sets the HTML used as the template and optionally compiles it.
5611      * @param {String} html
5612      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
5613      * @return {Roo.Template} this
5614      */
5615     set : function(html, compile){
5616         this.html = html;
5617         this.compiled = false;
5618         if(compile){
5619             this.compile();
5620         }
5621         return this;
5622     },
5623     
5624     /**
5625      * True to disable format functions (defaults to false)
5626      * @type Boolean
5627      */
5628     disableFormats : false,
5629     
5630     /**
5631     * The regular expression used to match template variables 
5632     * @type RegExp
5633     * @property 
5634     */
5635     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
5636     
5637     /**
5638      * Compiles the template into an internal function, eliminating the RegEx overhead.
5639      * @return {Roo.Template} this
5640      */
5641     compile : function(){
5642         var fm = Roo.util.Format;
5643         var useF = this.disableFormats !== true;
5644         var sep = Roo.isGecko ? "+" : ",";
5645         var fn = function(m, name, format, args){
5646             if(format && useF){
5647                 args = args ? ',' + args : "";
5648                 if(format.substr(0, 5) != "this."){
5649                     format = "fm." + format + '(';
5650                 }else{
5651                     format = 'this.call("'+ format.substr(5) + '", ';
5652                     args = ", values";
5653                 }
5654             }else{
5655                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
5656             }
5657             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
5658         };
5659         var body;
5660         // branched to use + in gecko and [].join() in others
5661         if(Roo.isGecko){
5662             body = "this.compiled = function(values){ return '" +
5663                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
5664                     "';};";
5665         }else{
5666             body = ["this.compiled = function(values){ return ['"];
5667             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
5668             body.push("'].join('');};");
5669             body = body.join('');
5670         }
5671         /**
5672          * eval:var:values
5673          * eval:var:fm
5674          */
5675         eval(body);
5676         return this;
5677     },
5678     
5679     // private function used to call members
5680     call : function(fnName, value, allValues){
5681         return this[fnName](value, allValues);
5682     },
5683     
5684     /**
5685      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
5686      * @param {String/HTMLElement/Roo.Element} el The context element
5687      * @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'})
5688      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
5689      * @return {HTMLElement/Roo.Element} The new node or Element
5690      */
5691     insertFirst: function(el, values, returnElement){
5692         return this.doInsert('afterBegin', el, values, returnElement);
5693     },
5694
5695     /**
5696      * Applies the supplied values to the template and inserts the new node(s) before el.
5697      * @param {String/HTMLElement/Roo.Element} el The context element
5698      * @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'})
5699      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
5700      * @return {HTMLElement/Roo.Element} The new node or Element
5701      */
5702     insertBefore: function(el, values, returnElement){
5703         return this.doInsert('beforeBegin', el, values, returnElement);
5704     },
5705
5706     /**
5707      * Applies the supplied values to the template and inserts the new node(s) after el.
5708      * @param {String/HTMLElement/Roo.Element} el The context element
5709      * @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'})
5710      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
5711      * @return {HTMLElement/Roo.Element} The new node or Element
5712      */
5713     insertAfter : function(el, values, returnElement){
5714         return this.doInsert('afterEnd', el, values, returnElement);
5715     },
5716     
5717     /**
5718      * Applies the supplied values to the template and appends the new node(s) to el.
5719      * @param {String/HTMLElement/Roo.Element} el The context element
5720      * @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'})
5721      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
5722      * @return {HTMLElement/Roo.Element} The new node or Element
5723      */
5724     append : function(el, values, returnElement){
5725         return this.doInsert('beforeEnd', el, values, returnElement);
5726     },
5727
5728     doInsert : function(where, el, values, returnEl){
5729         el = Roo.getDom(el);
5730         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
5731         return returnEl ? Roo.get(newNode, true) : newNode;
5732     },
5733
5734     /**
5735      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
5736      * @param {String/HTMLElement/Roo.Element} el The context element
5737      * @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'})
5738      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
5739      * @return {HTMLElement/Roo.Element} The new node or Element
5740      */
5741     overwrite : function(el, values, returnElement){
5742         el = Roo.getDom(el);
5743         el.innerHTML = this.applyTemplate(values);
5744         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
5745     }
5746 };
5747 /**
5748  * Alias for {@link #applyTemplate}
5749  * @method
5750  */
5751 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
5752
5753 // backwards compat
5754 Roo.DomHelper.Template = Roo.Template;
5755
5756 /**
5757  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
5758  * @param {String/HTMLElement} el A DOM element or its id
5759  * @returns {Roo.Template} The created template
5760  * @static
5761  */
5762 Roo.Template.from = function(el){
5763     el = Roo.getDom(el);
5764     return new Roo.Template(el.value || el.innerHTML);
5765 };/*
5766  * Based on:
5767  * Ext JS Library 1.1.1
5768  * Copyright(c) 2006-2007, Ext JS, LLC.
5769  *
5770  * Originally Released Under LGPL - original licence link has changed is not relivant.
5771  *
5772  * Fork - LGPL
5773  * <script type="text/javascript">
5774  */
5775  
5776
5777 /*
5778  * This is code is also distributed under MIT license for use
5779  * with jQuery and prototype JavaScript libraries.
5780  */
5781 /**
5782  * @class Roo.DomQuery
5783 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).
5784 <p>
5785 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>
5786
5787 <p>
5788 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.
5789 </p>
5790 <h4>Element Selectors:</h4>
5791 <ul class="list">
5792     <li> <b>*</b> any element</li>
5793     <li> <b>E</b> an element with the tag E</li>
5794     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
5795     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
5796     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
5797     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
5798 </ul>
5799 <h4>Attribute Selectors:</h4>
5800 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
5801 <ul class="list">
5802     <li> <b>E[foo]</b> has an attribute "foo"</li>
5803     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
5804     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
5805     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
5806     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
5807     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
5808     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
5809 </ul>
5810 <h4>Pseudo Classes:</h4>
5811 <ul class="list">
5812     <li> <b>E:first-child</b> E is the first child of its parent</li>
5813     <li> <b>E:last-child</b> E is the last child of its parent</li>
5814     <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>
5815     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
5816     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
5817     <li> <b>E:only-child</b> E is the only child of its parent</li>
5818     <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>
5819     <li> <b>E:first</b> the first E in the resultset</li>
5820     <li> <b>E:last</b> the last E in the resultset</li>
5821     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
5822     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
5823     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
5824     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
5825     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
5826     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
5827     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
5828     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
5829     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
5830 </ul>
5831 <h4>CSS Value Selectors:</h4>
5832 <ul class="list">
5833     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
5834     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
5835     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
5836     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
5837     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
5838     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
5839 </ul>
5840  * @static
5841  */
5842 Roo.DomQuery = function(){
5843     var cache = {}, simpleCache = {}, valueCache = {};
5844     var nonSpace = /\S/;
5845     var trimRe = /^\s+|\s+$/g;
5846     var tplRe = /\{(\d+)\}/g;
5847     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
5848     var tagTokenRe = /^(#)?([\w-\*]+)/;
5849     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
5850
5851     function child(p, index){
5852         var i = 0;
5853         var n = p.firstChild;
5854         while(n){
5855             if(n.nodeType == 1){
5856                if(++i == index){
5857                    return n;
5858                }
5859             }
5860             n = n.nextSibling;
5861         }
5862         return null;
5863     };
5864
5865     function next(n){
5866         while((n = n.nextSibling) && n.nodeType != 1);
5867         return n;
5868     };
5869
5870     function prev(n){
5871         while((n = n.previousSibling) && n.nodeType != 1);
5872         return n;
5873     };
5874
5875     function children(d){
5876         var n = d.firstChild, ni = -1;
5877             while(n){
5878                 var nx = n.nextSibling;
5879                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
5880                     d.removeChild(n);
5881                 }else{
5882                     n.nodeIndex = ++ni;
5883                 }
5884                 n = nx;
5885             }
5886             return this;
5887         };
5888
5889     function byClassName(c, a, v){
5890         if(!v){
5891             return c;
5892         }
5893         var r = [], ri = -1, cn;
5894         for(var i = 0, ci; ci = c[i]; i++){
5895             
5896             
5897             if((' '+
5898                 ( (ci instanceof SVGElement) ? ci.className.baseVal : ci.className)
5899                  +' ').indexOf(v) != -1){
5900                 r[++ri] = ci;
5901             }
5902         }
5903         return r;
5904     };
5905
5906     function attrValue(n, attr){
5907         if(!n.tagName && typeof n.length != "undefined"){
5908             n = n[0];
5909         }
5910         if(!n){
5911             return null;
5912         }
5913         if(attr == "for"){
5914             return n.htmlFor;
5915         }
5916         if(attr == "class" || attr == "className"){
5917             return (n instanceof SVGElement) ? n.className.baseVal : n.className;
5918         }
5919         return n.getAttribute(attr) || n[attr];
5920
5921     };
5922
5923     function getNodes(ns, mode, tagName){
5924         var result = [], ri = -1, cs;
5925         if(!ns){
5926             return result;
5927         }
5928         tagName = tagName || "*";
5929         if(typeof ns.getElementsByTagName != "undefined"){
5930             ns = [ns];
5931         }
5932         if(!mode){
5933             for(var i = 0, ni; ni = ns[i]; i++){
5934                 cs = ni.getElementsByTagName(tagName);
5935                 for(var j = 0, ci; ci = cs[j]; j++){
5936                     result[++ri] = ci;
5937                 }
5938             }
5939         }else if(mode == "/" || mode == ">"){
5940             var utag = tagName.toUpperCase();
5941             for(var i = 0, ni, cn; ni = ns[i]; i++){
5942                 cn = ni.children || ni.childNodes;
5943                 for(var j = 0, cj; cj = cn[j]; j++){
5944                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
5945                         result[++ri] = cj;
5946                     }
5947                 }
5948             }
5949         }else if(mode == "+"){
5950             var utag = tagName.toUpperCase();
5951             for(var i = 0, n; n = ns[i]; i++){
5952                 while((n = n.nextSibling) && n.nodeType != 1);
5953                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5954                     result[++ri] = n;
5955                 }
5956             }
5957         }else if(mode == "~"){
5958             for(var i = 0, n; n = ns[i]; i++){
5959                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5960                 if(n){
5961                     result[++ri] = n;
5962                 }
5963             }
5964         }
5965         return result;
5966     };
5967
5968     function concat(a, b){
5969         if(b.slice){
5970             return a.concat(b);
5971         }
5972         for(var i = 0, l = b.length; i < l; i++){
5973             a[a.length] = b[i];
5974         }
5975         return a;
5976     }
5977
5978     function byTag(cs, tagName){
5979         if(cs.tagName || cs == document){
5980             cs = [cs];
5981         }
5982         if(!tagName){
5983             return cs;
5984         }
5985         var r = [], ri = -1;
5986         tagName = tagName.toLowerCase();
5987         for(var i = 0, ci; ci = cs[i]; i++){
5988             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5989                 r[++ri] = ci;
5990             }
5991         }
5992         return r;
5993     };
5994
5995     function byId(cs, attr, id){
5996         if(cs.tagName || cs == document){
5997             cs = [cs];
5998         }
5999         if(!id){
6000             return cs;
6001         }
6002         var r = [], ri = -1;
6003         for(var i = 0,ci; ci = cs[i]; i++){
6004             if(ci && ci.id == id){
6005                 r[++ri] = ci;
6006                 return r;
6007             }
6008         }
6009         return r;
6010     };
6011
6012     function byAttribute(cs, attr, value, op, custom){
6013         var r = [], ri = -1, st = custom=="{";
6014         var f = Roo.DomQuery.operators[op];
6015         for(var i = 0, ci; ci = cs[i]; i++){
6016             var a;
6017             if(st){
6018                 a = Roo.DomQuery.getStyle(ci, attr);
6019             }
6020             else if(attr == "class" || attr == "className"){
6021                 a = (ci instanceof SVGElement) ? ci.className.baseVal : ci.className;
6022             }else if(attr == "for"){
6023                 a = ci.htmlFor;
6024             }else if(attr == "href"){
6025                 a = ci.getAttribute("href", 2);
6026             }else{
6027                 a = ci.getAttribute(attr);
6028             }
6029             if((f && f(a, value)) || (!f && a)){
6030                 r[++ri] = ci;
6031             }
6032         }
6033         return r;
6034     };
6035
6036     function byPseudo(cs, name, value){
6037         return Roo.DomQuery.pseudos[name](cs, value);
6038     };
6039
6040     // This is for IE MSXML which does not support expandos.
6041     // IE runs the same speed using setAttribute, however FF slows way down
6042     // and Safari completely fails so they need to continue to use expandos.
6043     var isIE = window.ActiveXObject ? true : false;
6044
6045     // this eval is stop the compressor from
6046     // renaming the variable to something shorter
6047     
6048     /** eval:var:batch */
6049     var batch = 30803; 
6050
6051     var key = 30803;
6052
6053     function nodupIEXml(cs){
6054         var d = ++key;
6055         cs[0].setAttribute("_nodup", d);
6056         var r = [cs[0]];
6057         for(var i = 1, len = cs.length; i < len; i++){
6058             var c = cs[i];
6059             if(!c.getAttribute("_nodup") != d){
6060                 c.setAttribute("_nodup", d);
6061                 r[r.length] = c;
6062             }
6063         }
6064         for(var i = 0, len = cs.length; i < len; i++){
6065             cs[i].removeAttribute("_nodup");
6066         }
6067         return r;
6068     }
6069
6070     function nodup(cs){
6071         if(!cs){
6072             return [];
6073         }
6074         var len = cs.length, c, i, r = cs, cj, ri = -1;
6075         if(!len || typeof cs.nodeType != "undefined" || len == 1){
6076             return cs;
6077         }
6078         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
6079             return nodupIEXml(cs);
6080         }
6081         var d = ++key;
6082         cs[0]._nodup = d;
6083         for(i = 1; c = cs[i]; i++){
6084             if(c._nodup != d){
6085                 c._nodup = d;
6086             }else{
6087                 r = [];
6088                 for(var j = 0; j < i; j++){
6089                     r[++ri] = cs[j];
6090                 }
6091                 for(j = i+1; cj = cs[j]; j++){
6092                     if(cj._nodup != d){
6093                         cj._nodup = d;
6094                         r[++ri] = cj;
6095                     }
6096                 }
6097                 return r;
6098             }
6099         }
6100         return r;
6101     }
6102
6103     function quickDiffIEXml(c1, c2){
6104         var d = ++key;
6105         for(var i = 0, len = c1.length; i < len; i++){
6106             c1[i].setAttribute("_qdiff", d);
6107         }
6108         var r = [];
6109         for(var i = 0, len = c2.length; i < len; i++){
6110             if(c2[i].getAttribute("_qdiff") != d){
6111                 r[r.length] = c2[i];
6112             }
6113         }
6114         for(var i = 0, len = c1.length; i < len; i++){
6115            c1[i].removeAttribute("_qdiff");
6116         }
6117         return r;
6118     }
6119
6120     function quickDiff(c1, c2){
6121         var len1 = c1.length;
6122         if(!len1){
6123             return c2;
6124         }
6125         if(isIE && c1[0].selectSingleNode){
6126             return quickDiffIEXml(c1, c2);
6127         }
6128         var d = ++key;
6129         for(var i = 0; i < len1; i++){
6130             c1[i]._qdiff = d;
6131         }
6132         var r = [];
6133         for(var i = 0, len = c2.length; i < len; i++){
6134             if(c2[i]._qdiff != d){
6135                 r[r.length] = c2[i];
6136             }
6137         }
6138         return r;
6139     }
6140
6141     function quickId(ns, mode, root, id){
6142         if(ns == root){
6143            var d = root.ownerDocument || root;
6144            return d.getElementById(id);
6145         }
6146         ns = getNodes(ns, mode, "*");
6147         return byId(ns, null, id);
6148     }
6149
6150     return {
6151         getStyle : function(el, name){
6152             return Roo.fly(el).getStyle(name);
6153         },
6154         /**
6155          * Compiles a selector/xpath query into a reusable function. The returned function
6156          * takes one parameter "root" (optional), which is the context node from where the query should start.
6157          * @param {String} selector The selector/xpath query
6158          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
6159          * @return {Function}
6160          */
6161         compile : function(path, type){
6162             type = type || "select";
6163             
6164             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
6165             var q = path, mode, lq;
6166             var tk = Roo.DomQuery.matchers;
6167             var tklen = tk.length;
6168             var mm;
6169
6170             // accept leading mode switch
6171             var lmode = q.match(modeRe);
6172             if(lmode && lmode[1]){
6173                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
6174                 q = q.replace(lmode[1], "");
6175             }
6176             // strip leading slashes
6177             while(path.substr(0, 1)=="/"){
6178                 path = path.substr(1);
6179             }
6180
6181             while(q && lq != q){
6182                 lq = q;
6183                 var tm = q.match(tagTokenRe);
6184                 if(type == "select"){
6185                     if(tm){
6186                         if(tm[1] == "#"){
6187                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
6188                         }else{
6189                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
6190                         }
6191                         q = q.replace(tm[0], "");
6192                     }else if(q.substr(0, 1) != '@'){
6193                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
6194                     }
6195                 }else{
6196                     if(tm){
6197                         if(tm[1] == "#"){
6198                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
6199                         }else{
6200                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
6201                         }
6202                         q = q.replace(tm[0], "");
6203                     }
6204                 }
6205                 while(!(mm = q.match(modeRe))){
6206                     var matched = false;
6207                     for(var j = 0; j < tklen; j++){
6208                         var t = tk[j];
6209                         var m = q.match(t.re);
6210                         if(m){
6211                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
6212                                                     return m[i];
6213                                                 });
6214                             q = q.replace(m[0], "");
6215                             matched = true;
6216                             break;
6217                         }
6218                     }
6219                     // prevent infinite loop on bad selector
6220                     if(!matched){
6221                         throw 'Error parsing selector, parsing failed at "' + q + '"';
6222                     }
6223                 }
6224                 if(mm[1]){
6225                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
6226                     q = q.replace(mm[1], "");
6227                 }
6228             }
6229             fn[fn.length] = "return nodup(n);\n}";
6230             
6231              /** 
6232               * list of variables that need from compression as they are used by eval.
6233              *  eval:var:batch 
6234              *  eval:var:nodup
6235              *  eval:var:byTag
6236              *  eval:var:ById
6237              *  eval:var:getNodes
6238              *  eval:var:quickId
6239              *  eval:var:mode
6240              *  eval:var:root
6241              *  eval:var:n
6242              *  eval:var:byClassName
6243              *  eval:var:byPseudo
6244              *  eval:var:byAttribute
6245              *  eval:var:attrValue
6246              * 
6247              **/ 
6248             eval(fn.join(""));
6249             return f;
6250         },
6251
6252         /**
6253          * Selects a group of elements.
6254          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
6255          * @param {Node} root (optional) The start of the query (defaults to document).
6256          * @return {Array}
6257          */
6258         select : function(path, root, type){
6259             if(!root || root == document){
6260                 root = document;
6261             }
6262             if(typeof root == "string"){
6263                 root = document.getElementById(root);
6264             }
6265             var paths = path.split(",");
6266             var results = [];
6267             for(var i = 0, len = paths.length; i < len; i++){
6268                 var p = paths[i].replace(trimRe, "");
6269                 if(!cache[p]){
6270                     cache[p] = Roo.DomQuery.compile(p);
6271                     if(!cache[p]){
6272                         throw p + " is not a valid selector";
6273                     }
6274                 }
6275                 var result = cache[p](root);
6276                 if(result && result != document){
6277                     results = results.concat(result);
6278                 }
6279             }
6280             if(paths.length > 1){
6281                 return nodup(results);
6282             }
6283             return results;
6284         },
6285
6286         /**
6287          * Selects a single element.
6288          * @param {String} selector The selector/xpath query
6289          * @param {Node} root (optional) The start of the query (defaults to document).
6290          * @return {Element}
6291          */
6292         selectNode : function(path, root){
6293             return Roo.DomQuery.select(path, root)[0];
6294         },
6295
6296         /**
6297          * Selects the value of a node, optionally replacing null with the defaultValue.
6298          * @param {String} selector The selector/xpath query
6299          * @param {Node} root (optional) The start of the query (defaults to document).
6300          * @param {String} defaultValue
6301          */
6302         selectValue : function(path, root, defaultValue){
6303             path = path.replace(trimRe, "");
6304             if(!valueCache[path]){
6305                 valueCache[path] = Roo.DomQuery.compile(path, "select");
6306             }
6307             var n = valueCache[path](root);
6308             n = n[0] ? n[0] : n;
6309             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
6310             return ((v === null||v === undefined||v==='') ? defaultValue : v);
6311         },
6312
6313         /**
6314          * Selects the value of a node, parsing integers and floats.
6315          * @param {String} selector The selector/xpath query
6316          * @param {Node} root (optional) The start of the query (defaults to document).
6317          * @param {Number} defaultValue
6318          * @return {Number}
6319          */
6320         selectNumber : function(path, root, defaultValue){
6321             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
6322             return parseFloat(v);
6323         },
6324
6325         /**
6326          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
6327          * @param {String/HTMLElement/Array} el An element id, element or array of elements
6328          * @param {String} selector The simple selector to test
6329          * @return {Boolean}
6330          */
6331         is : function(el, ss){
6332             if(typeof el == "string"){
6333                 el = document.getElementById(el);
6334             }
6335             var isArray = (el instanceof Array);
6336             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
6337             return isArray ? (result.length == el.length) : (result.length > 0);
6338         },
6339
6340         /**
6341          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
6342          * @param {Array} el An array of elements to filter
6343          * @param {String} selector The simple selector to test
6344          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
6345          * the selector instead of the ones that match
6346          * @return {Array}
6347          */
6348         filter : function(els, ss, nonMatches){
6349             ss = ss.replace(trimRe, "");
6350             if(!simpleCache[ss]){
6351                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
6352             }
6353             var result = simpleCache[ss](els);
6354             return nonMatches ? quickDiff(result, els) : result;
6355         },
6356
6357         /**
6358          * Collection of matching regular expressions and code snippets.
6359          */
6360         matchers : [{
6361                 re: /^\.([\w-]+)/,
6362                 select: 'n = byClassName(n, null, " {1} ");'
6363             }, {
6364                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
6365                 select: 'n = byPseudo(n, "{1}", "{2}");'
6366             },{
6367                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
6368                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
6369             }, {
6370                 re: /^#([\w-]+)/,
6371                 select: 'n = byId(n, null, "{1}");'
6372             },{
6373                 re: /^@([\w-]+)/,
6374                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
6375             }
6376         ],
6377
6378         /**
6379          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
6380          * 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;.
6381          */
6382         operators : {
6383             "=" : function(a, v){
6384                 return a == v;
6385             },
6386             "!=" : function(a, v){
6387                 return a != v;
6388             },
6389             "^=" : function(a, v){
6390                 return a && a.substr(0, v.length) == v;
6391             },
6392             "$=" : function(a, v){
6393                 return a && a.substr(a.length-v.length) == v;
6394             },
6395             "*=" : function(a, v){
6396                 return a && a.indexOf(v) !== -1;
6397             },
6398             "%=" : function(a, v){
6399                 return (a % v) == 0;
6400             },
6401             "|=" : function(a, v){
6402                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
6403             },
6404             "~=" : function(a, v){
6405                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
6406             }
6407         },
6408
6409         /**
6410          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
6411          * and the argument (if any) supplied in the selector.
6412          */
6413         pseudos : {
6414             "first-child" : function(c){
6415                 var r = [], ri = -1, n;
6416                 for(var i = 0, ci; ci = n = c[i]; i++){
6417                     while((n = n.previousSibling) && n.nodeType != 1);
6418                     if(!n){
6419                         r[++ri] = ci;
6420                     }
6421                 }
6422                 return r;
6423             },
6424
6425             "last-child" : function(c){
6426                 var r = [], ri = -1, n;
6427                 for(var i = 0, ci; ci = n = c[i]; i++){
6428                     while((n = n.nextSibling) && n.nodeType != 1);
6429                     if(!n){
6430                         r[++ri] = ci;
6431                     }
6432                 }
6433                 return r;
6434             },
6435
6436             "nth-child" : function(c, a) {
6437                 var r = [], ri = -1;
6438                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
6439                 var f = (m[1] || 1) - 0, l = m[2] - 0;
6440                 for(var i = 0, n; n = c[i]; i++){
6441                     var pn = n.parentNode;
6442                     if (batch != pn._batch) {
6443                         var j = 0;
6444                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
6445                             if(cn.nodeType == 1){
6446                                cn.nodeIndex = ++j;
6447                             }
6448                         }
6449                         pn._batch = batch;
6450                     }
6451                     if (f == 1) {
6452                         if (l == 0 || n.nodeIndex == l){
6453                             r[++ri] = n;
6454                         }
6455                     } else if ((n.nodeIndex + l) % f == 0){
6456                         r[++ri] = n;
6457                     }
6458                 }
6459
6460                 return r;
6461             },
6462
6463             "only-child" : function(c){
6464                 var r = [], ri = -1;;
6465                 for(var i = 0, ci; ci = c[i]; i++){
6466                     if(!prev(ci) && !next(ci)){
6467                         r[++ri] = ci;
6468                     }
6469                 }
6470                 return r;
6471             },
6472
6473             "empty" : function(c){
6474                 var r = [], ri = -1;
6475                 for(var i = 0, ci; ci = c[i]; i++){
6476                     var cns = ci.childNodes, j = 0, cn, empty = true;
6477                     while(cn = cns[j]){
6478                         ++j;
6479                         if(cn.nodeType == 1 || cn.nodeType == 3){
6480                             empty = false;
6481                             break;
6482                         }
6483                     }
6484                     if(empty){
6485                         r[++ri] = ci;
6486                     }
6487                 }
6488                 return r;
6489             },
6490
6491             "contains" : function(c, v){
6492                 var r = [], ri = -1;
6493                 for(var i = 0, ci; ci = c[i]; i++){
6494                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
6495                         r[++ri] = ci;
6496                     }
6497                 }
6498                 return r;
6499             },
6500
6501             "nodeValue" : function(c, v){
6502                 var r = [], ri = -1;
6503                 for(var i = 0, ci; ci = c[i]; i++){
6504                     if(ci.firstChild && ci.firstChild.nodeValue == v){
6505                         r[++ri] = ci;
6506                     }
6507                 }
6508                 return r;
6509             },
6510
6511             "checked" : function(c){
6512                 var r = [], ri = -1;
6513                 for(var i = 0, ci; ci = c[i]; i++){
6514                     if(ci.checked == true){
6515                         r[++ri] = ci;
6516                     }
6517                 }
6518                 return r;
6519             },
6520
6521             "not" : function(c, ss){
6522                 return Roo.DomQuery.filter(c, ss, true);
6523             },
6524
6525             "odd" : function(c){
6526                 return this["nth-child"](c, "odd");
6527             },
6528
6529             "even" : function(c){
6530                 return this["nth-child"](c, "even");
6531             },
6532
6533             "nth" : function(c, a){
6534                 return c[a-1] || [];
6535             },
6536
6537             "first" : function(c){
6538                 return c[0] || [];
6539             },
6540
6541             "last" : function(c){
6542                 return c[c.length-1] || [];
6543             },
6544
6545             "has" : function(c, ss){
6546                 var s = Roo.DomQuery.select;
6547                 var r = [], ri = -1;
6548                 for(var i = 0, ci; ci = c[i]; i++){
6549                     if(s(ss, ci).length > 0){
6550                         r[++ri] = ci;
6551                     }
6552                 }
6553                 return r;
6554             },
6555
6556             "next" : function(c, ss){
6557                 var is = Roo.DomQuery.is;
6558                 var r = [], ri = -1;
6559                 for(var i = 0, ci; ci = c[i]; i++){
6560                     var n = next(ci);
6561                     if(n && is(n, ss)){
6562                         r[++ri] = ci;
6563                     }
6564                 }
6565                 return r;
6566             },
6567
6568             "prev" : function(c, ss){
6569                 var is = Roo.DomQuery.is;
6570                 var r = [], ri = -1;
6571                 for(var i = 0, ci; ci = c[i]; i++){
6572                     var n = prev(ci);
6573                     if(n && is(n, ss)){
6574                         r[++ri] = ci;
6575                     }
6576                 }
6577                 return r;
6578             }
6579         }
6580     };
6581 }();
6582
6583 /**
6584  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
6585  * @param {String} path The selector/xpath query
6586  * @param {Node} root (optional) The start of the query (defaults to document).
6587  * @return {Array}
6588  * @member Roo
6589  * @method query
6590  */
6591 Roo.query = Roo.DomQuery.select;
6592 /*
6593  * Based on:
6594  * Ext JS Library 1.1.1
6595  * Copyright(c) 2006-2007, Ext JS, LLC.
6596  *
6597  * Originally Released Under LGPL - original licence link has changed is not relivant.
6598  *
6599  * Fork - LGPL
6600  * <script type="text/javascript">
6601  */
6602
6603 /**
6604  * @class Roo.util.Observable
6605  * Base class that provides a common interface for publishing events. Subclasses are expected to
6606  * to have a property "events" with all the events defined.<br>
6607  * For example:
6608  * <pre><code>
6609  Employee = function(name){
6610     this.name = name;
6611     this.addEvents({
6612         "fired" : true,
6613         "quit" : true
6614     });
6615  }
6616  Roo.extend(Employee, Roo.util.Observable);
6617 </code></pre>
6618  * @param {Object} config properties to use (incuding events / listeners)
6619  */
6620
6621 Roo.util.Observable = function(cfg){
6622     
6623     cfg = cfg|| {};
6624     this.addEvents(cfg.events || {});
6625     if (cfg.events) {
6626         delete cfg.events; // make sure
6627     }
6628      
6629     Roo.apply(this, cfg);
6630     
6631     if(this.listeners){
6632         this.on(this.listeners);
6633         delete this.listeners;
6634     }
6635 };
6636 Roo.util.Observable.prototype = {
6637     /** 
6638  * @cfg {Object} listeners  list of events and functions to call for this object, 
6639  * For example :
6640  * <pre><code>
6641     listeners :  { 
6642        'click' : function(e) {
6643            ..... 
6644         } ,
6645         .... 
6646     } 
6647   </code></pre>
6648  */
6649     
6650     
6651     /**
6652      * Fires the specified event with the passed parameters (minus the event name).
6653      * @param {String} eventName
6654      * @param {Object...} args Variable number of parameters are passed to handlers
6655      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
6656      */
6657     fireEvent : function(){
6658         var ce = this.events[arguments[0].toLowerCase()];
6659         if(typeof ce == "object"){
6660             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
6661         }else{
6662             return true;
6663         }
6664     },
6665
6666     // private
6667     filterOptRe : /^(?:scope|delay|buffer|single)$/,
6668
6669     /**
6670      * Appends an event handler to this component
6671      * @param {String}   eventName The type of event to listen for
6672      * @param {Function} handler The method the event invokes
6673      * @param {Object}   scope (optional) The scope in which to execute the handler
6674      * function. The handler function's "this" context.
6675      * @param {Object}   options (optional) An object containing handler configuration
6676      * properties. This may contain any of the following properties:<ul>
6677      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6678      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6679      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6680      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6681      * by the specified number of milliseconds. If the event fires again within that time, the original
6682      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6683      * </ul><br>
6684      * <p>
6685      * <b>Combining Options</b><br>
6686      * Using the options argument, it is possible to combine different types of listeners:<br>
6687      * <br>
6688      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
6689                 <pre><code>
6690                 el.on('click', this.onClick, this, {
6691                         single: true,
6692                 delay: 100,
6693                 forumId: 4
6694                 });
6695                 </code></pre>
6696      * <p>
6697      * <b>Attaching multiple handlers in 1 call</b><br>
6698      * The method also allows for a single argument to be passed which is a config object containing properties
6699      * which specify multiple handlers.
6700      * <pre><code>
6701                 el.on({
6702                         'click': {
6703                         fn: this.onClick,
6704                         scope: this,
6705                         delay: 100
6706                 }, 
6707                 'mouseover': {
6708                         fn: this.onMouseOver,
6709                         scope: this
6710                 },
6711                 'mouseout': {
6712                         fn: this.onMouseOut,
6713                         scope: this
6714                 }
6715                 });
6716                 </code></pre>
6717      * <p>
6718      * Or a shorthand syntax which passes the same scope object to all handlers:
6719         <pre><code>
6720                 el.on({
6721                         'click': this.onClick,
6722                 'mouseover': this.onMouseOver,
6723                 'mouseout': this.onMouseOut,
6724                 scope: this
6725                 });
6726                 </code></pre>
6727      */
6728     addListener : function(eventName, fn, scope, o){
6729         if(typeof eventName == "object"){
6730             o = eventName;
6731             for(var e in o){
6732                 if(this.filterOptRe.test(e)){
6733                     continue;
6734                 }
6735                 if(typeof o[e] == "function"){
6736                     // shared options
6737                     this.addListener(e, o[e], o.scope,  o);
6738                 }else{
6739                     // individual options
6740                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
6741                 }
6742             }
6743             return;
6744         }
6745         o = (!o || typeof o == "boolean") ? {} : o;
6746         eventName = eventName.toLowerCase();
6747         var ce = this.events[eventName] || true;
6748         if(typeof ce == "boolean"){
6749             ce = new Roo.util.Event(this, eventName);
6750             this.events[eventName] = ce;
6751         }
6752         ce.addListener(fn, scope, o);
6753     },
6754
6755     /**
6756      * Removes a listener
6757      * @param {String}   eventName     The type of event to listen for
6758      * @param {Function} handler        The handler to remove
6759      * @param {Object}   scope  (optional) The scope (this object) for the handler
6760      */
6761     removeListener : function(eventName, fn, scope){
6762         var ce = this.events[eventName.toLowerCase()];
6763         if(typeof ce == "object"){
6764             ce.removeListener(fn, scope);
6765         }
6766     },
6767
6768     /**
6769      * Removes all listeners for this object
6770      */
6771     purgeListeners : function(){
6772         for(var evt in this.events){
6773             if(typeof this.events[evt] == "object"){
6774                  this.events[evt].clearListeners();
6775             }
6776         }
6777     },
6778
6779     relayEvents : function(o, events){
6780         var createHandler = function(ename){
6781             return function(){
6782                  
6783                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
6784             };
6785         };
6786         for(var i = 0, len = events.length; i < len; i++){
6787             var ename = events[i];
6788             if(!this.events[ename]){
6789                 this.events[ename] = true;
6790             };
6791             o.on(ename, createHandler(ename), this);
6792         }
6793     },
6794
6795     /**
6796      * Used to define events on this Observable
6797      * @param {Object} object The object with the events defined
6798      */
6799     addEvents : function(o){
6800         if(!this.events){
6801             this.events = {};
6802         }
6803         Roo.applyIf(this.events, o);
6804     },
6805
6806     /**
6807      * Checks to see if this object has any listeners for a specified event
6808      * @param {String} eventName The name of the event to check for
6809      * @return {Boolean} True if the event is being listened for, else false
6810      */
6811     hasListener : function(eventName){
6812         var e = this.events[eventName];
6813         return typeof e == "object" && e.listeners.length > 0;
6814     }
6815 };
6816 /**
6817  * Appends an event handler to this element (shorthand for addListener)
6818  * @param {String}   eventName     The type of event to listen for
6819  * @param {Function} handler        The method the event invokes
6820  * @param {Object}   scope (optional) The scope in which to execute the handler
6821  * function. The handler function's "this" context.
6822  * @param {Object}   options  (optional)
6823  * @method
6824  */
6825 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
6826 /**
6827  * Removes a listener (shorthand for removeListener)
6828  * @param {String}   eventName     The type of event to listen for
6829  * @param {Function} handler        The handler to remove
6830  * @param {Object}   scope  (optional) The scope (this object) for the handler
6831  * @method
6832  */
6833 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
6834
6835 /**
6836  * Starts capture on the specified Observable. All events will be passed
6837  * to the supplied function with the event name + standard signature of the event
6838  * <b>before</b> the event is fired. If the supplied function returns false,
6839  * the event will not fire.
6840  * @param {Observable} o The Observable to capture
6841  * @param {Function} fn The function to call
6842  * @param {Object} scope (optional) The scope (this object) for the fn
6843  * @static
6844  */
6845 Roo.util.Observable.capture = function(o, fn, scope){
6846     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
6847 };
6848
6849 /**
6850  * Removes <b>all</b> added captures from the Observable.
6851  * @param {Observable} o The Observable to release
6852  * @static
6853  */
6854 Roo.util.Observable.releaseCapture = function(o){
6855     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
6856 };
6857
6858 (function(){
6859
6860     var createBuffered = function(h, o, scope){
6861         var task = new Roo.util.DelayedTask();
6862         return function(){
6863             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
6864         };
6865     };
6866
6867     var createSingle = function(h, e, fn, scope){
6868         return function(){
6869             e.removeListener(fn, scope);
6870             return h.apply(scope, arguments);
6871         };
6872     };
6873
6874     var createDelayed = function(h, o, scope){
6875         return function(){
6876             var args = Array.prototype.slice.call(arguments, 0);
6877             setTimeout(function(){
6878                 h.apply(scope, args);
6879             }, o.delay || 10);
6880         };
6881     };
6882
6883     Roo.util.Event = function(obj, name){
6884         this.name = name;
6885         this.obj = obj;
6886         this.listeners = [];
6887     };
6888
6889     Roo.util.Event.prototype = {
6890         addListener : function(fn, scope, options){
6891             var o = options || {};
6892             scope = scope || this.obj;
6893             if(!this.isListening(fn, scope)){
6894                 var l = {fn: fn, scope: scope, options: o};
6895                 var h = fn;
6896                 if(o.delay){
6897                     h = createDelayed(h, o, scope);
6898                 }
6899                 if(o.single){
6900                     h = createSingle(h, this, fn, scope);
6901                 }
6902                 if(o.buffer){
6903                     h = createBuffered(h, o, scope);
6904                 }
6905                 l.fireFn = h;
6906                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
6907                     this.listeners.push(l);
6908                 }else{
6909                     this.listeners = this.listeners.slice(0);
6910                     this.listeners.push(l);
6911                 }
6912             }
6913         },
6914
6915         findListener : function(fn, scope){
6916             scope = scope || this.obj;
6917             var ls = this.listeners;
6918             for(var i = 0, len = ls.length; i < len; i++){
6919                 var l = ls[i];
6920                 if(l.fn == fn && l.scope == scope){
6921                     return i;
6922                 }
6923             }
6924             return -1;
6925         },
6926
6927         isListening : function(fn, scope){
6928             return this.findListener(fn, scope) != -1;
6929         },
6930
6931         removeListener : function(fn, scope){
6932             var index;
6933             if((index = this.findListener(fn, scope)) != -1){
6934                 if(!this.firing){
6935                     this.listeners.splice(index, 1);
6936                 }else{
6937                     this.listeners = this.listeners.slice(0);
6938                     this.listeners.splice(index, 1);
6939                 }
6940                 return true;
6941             }
6942             return false;
6943         },
6944
6945         clearListeners : function(){
6946             this.listeners = [];
6947         },
6948
6949         fire : function(){
6950             var ls = this.listeners, scope, len = ls.length;
6951             if(len > 0){
6952                 this.firing = true;
6953                 var args = Array.prototype.slice.call(arguments, 0);                
6954                 for(var i = 0; i < len; i++){
6955                     var l = ls[i];
6956                     if(l.fireFn.apply(l.scope||this.obj||window, args) === false){
6957                         this.firing = false;
6958                         return false;
6959                     }
6960                 }
6961                 this.firing = false;
6962             }
6963             return true;
6964         }
6965     };
6966 })();/*
6967  * RooJS Library 
6968  * Copyright(c) 2007-2017, Roo J Solutions Ltd
6969  *
6970  * Licence LGPL 
6971  *
6972  */
6973  
6974 /**
6975  * @class Roo.Document
6976  * @extends Roo.util.Observable
6977  * This is a convience class to wrap up the main document loading code.. , rather than adding Roo.onReady(......)
6978  * 
6979  * @param {Object} config the methods and properties of the 'base' class for the application.
6980  * 
6981  *  Generic Page handler - implement this to start your app..
6982  * 
6983  * eg.
6984  *  MyProject = new Roo.Document({
6985         events : {
6986             'load' : true // your events..
6987         },
6988         listeners : {
6989             'ready' : function() {
6990                 // fired on Roo.onReady()
6991             }
6992         }
6993  * 
6994  */
6995 Roo.Document = function(cfg) {
6996      
6997     this.addEvents({ 
6998         'ready' : true
6999     });
7000     Roo.util.Observable.call(this,cfg);
7001     
7002     var _this = this;
7003     
7004     Roo.onReady(function() {
7005         _this.fireEvent('ready');
7006     },null,false);
7007     
7008     
7009 }
7010
7011 Roo.extend(Roo.Document, Roo.util.Observable, {});/*
7012  * Based on:
7013  * Ext JS Library 1.1.1
7014  * Copyright(c) 2006-2007, Ext JS, LLC.
7015  *
7016  * Originally Released Under LGPL - original licence link has changed is not relivant.
7017  *
7018  * Fork - LGPL
7019  * <script type="text/javascript">
7020  */
7021
7022 /**
7023  * @class Roo.EventManager
7024  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
7025  * several useful events directly.
7026  * See {@link Roo.EventObject} for more details on normalized event objects.
7027  * @static
7028  */
7029 Roo.EventManager = function(){
7030     var docReadyEvent, docReadyProcId, docReadyState = false;
7031     var resizeEvent, resizeTask, textEvent, textSize;
7032     var E = Roo.lib.Event;
7033     var D = Roo.lib.Dom;
7034
7035     
7036     
7037
7038     var fireDocReady = function(){
7039         if(!docReadyState){
7040             docReadyState = true;
7041             Roo.isReady = true;
7042             if(docReadyProcId){
7043                 clearInterval(docReadyProcId);
7044             }
7045             if(Roo.isGecko || Roo.isOpera) {
7046                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
7047             }
7048             if(Roo.isIE){
7049                 var defer = document.getElementById("ie-deferred-loader");
7050                 if(defer){
7051                     defer.onreadystatechange = null;
7052                     defer.parentNode.removeChild(defer);
7053                 }
7054             }
7055             if(docReadyEvent){
7056                 docReadyEvent.fire();
7057                 docReadyEvent.clearListeners();
7058             }
7059         }
7060     };
7061     
7062     var initDocReady = function(){
7063         docReadyEvent = new Roo.util.Event();
7064         if(Roo.isGecko || Roo.isOpera) {
7065             document.addEventListener("DOMContentLoaded", fireDocReady, false);
7066         }else if(Roo.isIE){
7067             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
7068             var defer = document.getElementById("ie-deferred-loader");
7069             defer.onreadystatechange = function(){
7070                 if(this.readyState == "complete"){
7071                     fireDocReady();
7072                 }
7073             };
7074         }else if(Roo.isSafari){ 
7075             docReadyProcId = setInterval(function(){
7076                 var rs = document.readyState;
7077                 if(rs == "complete") {
7078                     fireDocReady();     
7079                  }
7080             }, 10);
7081         }
7082         // no matter what, make sure it fires on load
7083         E.on(window, "load", fireDocReady);
7084     };
7085
7086     var createBuffered = function(h, o){
7087         var task = new Roo.util.DelayedTask(h);
7088         return function(e){
7089             // create new event object impl so new events don't wipe out properties
7090             e = new Roo.EventObjectImpl(e);
7091             task.delay(o.buffer, h, null, [e]);
7092         };
7093     };
7094
7095     var createSingle = function(h, el, ename, fn){
7096         return function(e){
7097             Roo.EventManager.removeListener(el, ename, fn);
7098             h(e);
7099         };
7100     };
7101
7102     var createDelayed = function(h, o){
7103         return function(e){
7104             // create new event object impl so new events don't wipe out properties
7105             e = new Roo.EventObjectImpl(e);
7106             setTimeout(function(){
7107                 h(e);
7108             }, o.delay || 10);
7109         };
7110     };
7111     var transitionEndVal = false;
7112     
7113     var transitionEnd = function()
7114     {
7115         if (transitionEndVal) {
7116             return transitionEndVal;
7117         }
7118         var el = document.createElement('div');
7119
7120         var transEndEventNames = {
7121             WebkitTransition : 'webkitTransitionEnd',
7122             MozTransition    : 'transitionend',
7123             OTransition      : 'oTransitionEnd otransitionend',
7124             transition       : 'transitionend'
7125         };
7126     
7127         for (var name in transEndEventNames) {
7128             if (el.style[name] !== undefined) {
7129                 transitionEndVal = transEndEventNames[name];
7130                 return  transitionEndVal ;
7131             }
7132         }
7133     }
7134     
7135   
7136
7137     var listen = function(element, ename, opt, fn, scope)
7138     {
7139         var o = (!opt || typeof opt == "boolean") ? {} : opt;
7140         fn = fn || o.fn; scope = scope || o.scope;
7141         var el = Roo.getDom(element);
7142         
7143         
7144         if(!el){
7145             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
7146         }
7147         
7148         if (ename == 'transitionend') {
7149             ename = transitionEnd();
7150         }
7151         var h = function(e){
7152             e = Roo.EventObject.setEvent(e);
7153             var t;
7154             if(o.delegate){
7155                 t = e.getTarget(o.delegate, el);
7156                 if(!t){
7157                     return;
7158                 }
7159             }else{
7160                 t = e.target;
7161             }
7162             if(o.stopEvent === true){
7163                 e.stopEvent();
7164             }
7165             if(o.preventDefault === true){
7166                e.preventDefault();
7167             }
7168             if(o.stopPropagation === true){
7169                 e.stopPropagation();
7170             }
7171
7172             if(o.normalized === false){
7173                 e = e.browserEvent;
7174             }
7175
7176             fn.call(scope || el, e, t, o);
7177         };
7178         if(o.delay){
7179             h = createDelayed(h, o);
7180         }
7181         if(o.single){
7182             h = createSingle(h, el, ename, fn);
7183         }
7184         if(o.buffer){
7185             h = createBuffered(h, o);
7186         }
7187         
7188         fn._handlers = fn._handlers || [];
7189         
7190         
7191         fn._handlers.push([Roo.id(el), ename, h]);
7192         
7193         
7194          
7195         E.on(el, ename, h); // this adds the actuall listener to the object..
7196         
7197         
7198         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
7199             el.addEventListener("DOMMouseScroll", h, false);
7200             E.on(window, 'unload', function(){
7201                 el.removeEventListener("DOMMouseScroll", h, false);
7202             });
7203         }
7204         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
7205             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
7206         }
7207         return h;
7208     };
7209
7210     var stopListening = function(el, ename, fn){
7211         var id = Roo.id(el), hds = fn._handlers, hd = fn;
7212         if(hds){
7213             for(var i = 0, len = hds.length; i < len; i++){
7214                 var h = hds[i];
7215                 if(h[0] == id && h[1] == ename){
7216                     hd = h[2];
7217                     hds.splice(i, 1);
7218                     break;
7219                 }
7220             }
7221         }
7222         E.un(el, ename, hd);
7223         el = Roo.getDom(el);
7224         if(ename == "mousewheel" && el.addEventListener){
7225             el.removeEventListener("DOMMouseScroll", hd, false);
7226         }
7227         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
7228             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
7229         }
7230     };
7231
7232     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
7233     
7234     var pub = {
7235         
7236         
7237         /** 
7238          * Fix for doc tools
7239          * @scope Roo.EventManager
7240          */
7241         
7242         
7243         /** 
7244          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
7245          * object with a Roo.EventObject
7246          * @param {Function} fn        The method the event invokes
7247          * @param {Object}   scope    An object that becomes the scope of the handler
7248          * @param {boolean}  override If true, the obj passed in becomes
7249          *                             the execution scope of the listener
7250          * @return {Function} The wrapped function
7251          * @deprecated
7252          */
7253         wrap : function(fn, scope, override){
7254             return function(e){
7255                 Roo.EventObject.setEvent(e);
7256                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
7257             };
7258         },
7259         
7260         /**
7261      * Appends an event handler to an element (shorthand for addListener)
7262      * @param {String/HTMLElement}   element        The html element or id to assign the
7263      * @param {String}   eventName The type of event to listen for
7264      * @param {Function} handler The method the event invokes
7265      * @param {Object}   scope (optional) The scope in which to execute the handler
7266      * function. The handler function's "this" context.
7267      * @param {Object}   options (optional) An object containing handler configuration
7268      * properties. This may contain any of the following properties:<ul>
7269      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
7270      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
7271      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
7272      * <li>preventDefault {Boolean} True to prevent the default action</li>
7273      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
7274      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
7275      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
7276      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
7277      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
7278      * by the specified number of milliseconds. If the event fires again within that time, the original
7279      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
7280      * </ul><br>
7281      * <p>
7282      * <b>Combining Options</b><br>
7283      * Using the options argument, it is possible to combine different types of listeners:<br>
7284      * <br>
7285      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
7286      * Code:<pre><code>
7287 el.on('click', this.onClick, this, {
7288     single: true,
7289     delay: 100,
7290     stopEvent : true,
7291     forumId: 4
7292 });</code></pre>
7293      * <p>
7294      * <b>Attaching multiple handlers in 1 call</b><br>
7295       * The method also allows for a single argument to be passed which is a config object containing properties
7296      * which specify multiple handlers.
7297      * <p>
7298      * Code:<pre><code>
7299 el.on({
7300     'click' : {
7301         fn: this.onClick
7302         scope: this,
7303         delay: 100
7304     },
7305     'mouseover' : {
7306         fn: this.onMouseOver
7307         scope: this
7308     },
7309     'mouseout' : {
7310         fn: this.onMouseOut
7311         scope: this
7312     }
7313 });</code></pre>
7314      * <p>
7315      * Or a shorthand syntax:<br>
7316      * Code:<pre><code>
7317 el.on({
7318     'click' : this.onClick,
7319     'mouseover' : this.onMouseOver,
7320     'mouseout' : this.onMouseOut
7321     scope: this
7322 });</code></pre>
7323      */
7324         addListener : function(element, eventName, fn, scope, options){
7325             if(typeof eventName == "object"){
7326                 var o = eventName;
7327                 for(var e in o){
7328                     if(propRe.test(e)){
7329                         continue;
7330                     }
7331                     if(typeof o[e] == "function"){
7332                         // shared options
7333                         listen(element, e, o, o[e], o.scope);
7334                     }else{
7335                         // individual options
7336                         listen(element, e, o[e]);
7337                     }
7338                 }
7339                 return;
7340             }
7341             return listen(element, eventName, options, fn, scope);
7342         },
7343         
7344         /**
7345          * Removes an event handler
7346          *
7347          * @param {String/HTMLElement}   element        The id or html element to remove the 
7348          *                             event from
7349          * @param {String}   eventName     The type of event
7350          * @param {Function} fn
7351          * @return {Boolean} True if a listener was actually removed
7352          */
7353         removeListener : function(element, eventName, fn){
7354             return stopListening(element, eventName, fn);
7355         },
7356         
7357         /**
7358          * Fires when the document is ready (before onload and before images are loaded). Can be 
7359          * accessed shorthanded Roo.onReady().
7360          * @param {Function} fn        The method the event invokes
7361          * @param {Object}   scope    An  object that becomes the scope of the handler
7362          * @param {boolean}  options
7363          */
7364         onDocumentReady : function(fn, scope, options){
7365             if(docReadyState){ // if it already fired
7366                 docReadyEvent.addListener(fn, scope, options);
7367                 docReadyEvent.fire();
7368                 docReadyEvent.clearListeners();
7369                 return;
7370             }
7371             if(!docReadyEvent){
7372                 initDocReady();
7373             }
7374             docReadyEvent.addListener(fn, scope, options);
7375         },
7376         
7377         /**
7378          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
7379          * @param {Function} fn        The method the event invokes
7380          * @param {Object}   scope    An object that becomes the scope of the handler
7381          * @param {boolean}  options
7382          */
7383         onWindowResize : function(fn, scope, options)
7384         {
7385             if(!resizeEvent){
7386                 resizeEvent = new Roo.util.Event();
7387                 resizeTask = new Roo.util.DelayedTask(function(){
7388                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
7389                 });
7390                 E.on(window, "resize", function()
7391                 {
7392                     if (Roo.isIE) {
7393                         resizeTask.delay(50);
7394                     } else {
7395                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
7396                     }
7397                 });
7398             }
7399             resizeEvent.addListener(fn, scope, options);
7400         },
7401
7402         /**
7403          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
7404          * @param {Function} fn        The method the event invokes
7405          * @param {Object}   scope    An object that becomes the scope of the handler
7406          * @param {boolean}  options
7407          */
7408         onTextResize : function(fn, scope, options){
7409             if(!textEvent){
7410                 textEvent = new Roo.util.Event();
7411                 var textEl = new Roo.Element(document.createElement('div'));
7412                 textEl.dom.className = 'x-text-resize';
7413                 textEl.dom.innerHTML = 'X';
7414                 textEl.appendTo(document.body);
7415                 textSize = textEl.dom.offsetHeight;
7416                 setInterval(function(){
7417                     if(textEl.dom.offsetHeight != textSize){
7418                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
7419                     }
7420                 }, this.textResizeInterval);
7421             }
7422             textEvent.addListener(fn, scope, options);
7423         },
7424
7425         /**
7426          * Removes the passed window resize listener.
7427          * @param {Function} fn        The method the event invokes
7428          * @param {Object}   scope    The scope of handler
7429          */
7430         removeResizeListener : function(fn, scope){
7431             if(resizeEvent){
7432                 resizeEvent.removeListener(fn, scope);
7433             }
7434         },
7435
7436         // private
7437         fireResize : function(){
7438             if(resizeEvent){
7439                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
7440             }   
7441         },
7442         /**
7443          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
7444          */
7445         ieDeferSrc : false,
7446         /**
7447          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
7448          */
7449         textResizeInterval : 50
7450     };
7451     
7452     /**
7453      * Fix for doc tools
7454      * @scopeAlias pub=Roo.EventManager
7455      */
7456     
7457      /**
7458      * Appends an event handler to an element (shorthand for addListener)
7459      * @param {String/HTMLElement}   element        The html element or id to assign the
7460      * @param {String}   eventName The type of event to listen for
7461      * @param {Function} handler The method the event invokes
7462      * @param {Object}   scope (optional) The scope in which to execute the handler
7463      * function. The handler function's "this" context.
7464      * @param {Object}   options (optional) An object containing handler configuration
7465      * properties. This may contain any of the following properties:<ul>
7466      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
7467      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
7468      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
7469      * <li>preventDefault {Boolean} True to prevent the default action</li>
7470      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
7471      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
7472      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
7473      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
7474      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
7475      * by the specified number of milliseconds. If the event fires again within that time, the original
7476      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
7477      * </ul><br>
7478      * <p>
7479      * <b>Combining Options</b><br>
7480      * Using the options argument, it is possible to combine different types of listeners:<br>
7481      * <br>
7482      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
7483      * Code:<pre><code>
7484 el.on('click', this.onClick, this, {
7485     single: true,
7486     delay: 100,
7487     stopEvent : true,
7488     forumId: 4
7489 });</code></pre>
7490      * <p>
7491      * <b>Attaching multiple handlers in 1 call</b><br>
7492       * The method also allows for a single argument to be passed which is a config object containing properties
7493      * which specify multiple handlers.
7494      * <p>
7495      * Code:<pre><code>
7496 el.on({
7497     'click' : {
7498         fn: this.onClick
7499         scope: this,
7500         delay: 100
7501     },
7502     'mouseover' : {
7503         fn: this.onMouseOver
7504         scope: this
7505     },
7506     'mouseout' : {
7507         fn: this.onMouseOut
7508         scope: this
7509     }
7510 });</code></pre>
7511      * <p>
7512      * Or a shorthand syntax:<br>
7513      * Code:<pre><code>
7514 el.on({
7515     'click' : this.onClick,
7516     'mouseover' : this.onMouseOver,
7517     'mouseout' : this.onMouseOut
7518     scope: this
7519 });</code></pre>
7520      */
7521     pub.on = pub.addListener;
7522     pub.un = pub.removeListener;
7523
7524     pub.stoppedMouseDownEvent = new Roo.util.Event();
7525     return pub;
7526 }();
7527 /**
7528   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
7529   * @param {Function} fn        The method the event invokes
7530   * @param {Object}   scope    An  object that becomes the scope of the handler
7531   * @param {boolean}  override If true, the obj passed in becomes
7532   *                             the execution scope of the listener
7533   * @member Roo
7534   * @method onReady
7535  */
7536 Roo.onReady = Roo.EventManager.onDocumentReady;
7537
7538 Roo.onReady(function(){
7539     var bd = Roo.get(document.body);
7540     if(!bd){ return; }
7541
7542     var cls = [
7543             Roo.isIE ? "roo-ie"
7544             : Roo.isIE11 ? "roo-ie11"
7545             : Roo.isEdge ? "roo-edge"
7546             : Roo.isGecko ? "roo-gecko"
7547             : Roo.isOpera ? "roo-opera"
7548             : Roo.isSafari ? "roo-safari" : ""];
7549
7550     if(Roo.isMac){
7551         cls.push("roo-mac");
7552     }
7553     if(Roo.isLinux){
7554         cls.push("roo-linux");
7555     }
7556     if(Roo.isIOS){
7557         cls.push("roo-ios");
7558     }
7559     if(Roo.isTouch){
7560         cls.push("roo-touch");
7561     }
7562     if(Roo.isBorderBox){
7563         cls.push('roo-border-box');
7564     }
7565     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
7566         var p = bd.dom.parentNode;
7567         if(p){
7568             p.className += ' roo-strict';
7569         }
7570     }
7571     bd.addClass(cls.join(' '));
7572 });
7573
7574 /**
7575  * @class Roo.EventObject
7576  * EventObject exposes the Yahoo! UI Event functionality directly on the object
7577  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
7578  * Example:
7579  * <pre><code>
7580  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
7581     e.preventDefault();
7582     var target = e.getTarget();
7583     ...
7584  }
7585  var myDiv = Roo.get("myDiv");
7586  myDiv.on("click", handleClick);
7587  //or
7588  Roo.EventManager.on("myDiv", 'click', handleClick);
7589  Roo.EventManager.addListener("myDiv", 'click', handleClick);
7590  </code></pre>
7591  * @static
7592  */
7593 Roo.EventObject = function(){
7594     
7595     var E = Roo.lib.Event;
7596     
7597     // safari keypress events for special keys return bad keycodes
7598     var safariKeys = {
7599         63234 : 37, // left
7600         63235 : 39, // right
7601         63232 : 38, // up
7602         63233 : 40, // down
7603         63276 : 33, // page up
7604         63277 : 34, // page down
7605         63272 : 46, // delete
7606         63273 : 36, // home
7607         63275 : 35  // end
7608     };
7609
7610     // normalize button clicks
7611     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
7612                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
7613
7614     Roo.EventObjectImpl = function(e){
7615         if(e){
7616             this.setEvent(e.browserEvent || e);
7617         }
7618     };
7619     Roo.EventObjectImpl.prototype = {
7620         /**
7621          * Used to fix doc tools.
7622          * @scope Roo.EventObject.prototype
7623          */
7624             
7625
7626         
7627         
7628         /** The normal browser event */
7629         browserEvent : null,
7630         /** The button pressed in a mouse event */
7631         button : -1,
7632         /** True if the shift key was down during the event */
7633         shiftKey : false,
7634         /** True if the control key was down during the event */
7635         ctrlKey : false,
7636         /** True if the alt key was down during the event */
7637         altKey : false,
7638
7639         /** Key constant 
7640         * @type Number */
7641         BACKSPACE : 8,
7642         /** Key constant 
7643         * @type Number */
7644         TAB : 9,
7645         /** Key constant 
7646         * @type Number */
7647         RETURN : 13,
7648         /** Key constant 
7649         * @type Number */
7650         ENTER : 13,
7651         /** Key constant 
7652         * @type Number */
7653         SHIFT : 16,
7654         /** Key constant 
7655         * @type Number */
7656         CONTROL : 17,
7657         /** Key constant 
7658         * @type Number */
7659         ESC : 27,
7660         /** Key constant 
7661         * @type Number */
7662         SPACE : 32,
7663         /** Key constant 
7664         * @type Number */
7665         PAGEUP : 33,
7666         /** Key constant 
7667         * @type Number */
7668         PAGEDOWN : 34,
7669         /** Key constant 
7670         * @type Number */
7671         END : 35,
7672         /** Key constant 
7673         * @type Number */
7674         HOME : 36,
7675         /** Key constant 
7676         * @type Number */
7677         LEFT : 37,
7678         /** Key constant 
7679         * @type Number */
7680         UP : 38,
7681         /** Key constant 
7682         * @type Number */
7683         RIGHT : 39,
7684         /** Key constant 
7685         * @type Number */
7686         DOWN : 40,
7687         /** Key constant 
7688         * @type Number */
7689         DELETE : 46,
7690         /** Key constant 
7691         * @type Number */
7692         F5 : 116,
7693
7694            /** @private */
7695         setEvent : function(e){
7696             if(e == this || (e && e.browserEvent)){ // already wrapped
7697                 return e;
7698             }
7699             this.browserEvent = e;
7700             if(e){
7701                 // normalize buttons
7702                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
7703                 if(e.type == 'click' && this.button == -1){
7704                     this.button = 0;
7705                 }
7706                 this.type = e.type;
7707                 this.shiftKey = e.shiftKey;
7708                 // mac metaKey behaves like ctrlKey
7709                 this.ctrlKey = e.ctrlKey || e.metaKey;
7710                 this.altKey = e.altKey;
7711                 // in getKey these will be normalized for the mac
7712                 this.keyCode = e.keyCode;
7713                 // keyup warnings on firefox.
7714                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
7715                 // cache the target for the delayed and or buffered events
7716                 this.target = E.getTarget(e);
7717                 // same for XY
7718                 this.xy = E.getXY(e);
7719             }else{
7720                 this.button = -1;
7721                 this.shiftKey = false;
7722                 this.ctrlKey = false;
7723                 this.altKey = false;
7724                 this.keyCode = 0;
7725                 this.charCode =0;
7726                 this.target = null;
7727                 this.xy = [0, 0];
7728             }
7729             return this;
7730         },
7731
7732         /**
7733          * Stop the event (preventDefault and stopPropagation)
7734          */
7735         stopEvent : function(){
7736             if(this.browserEvent){
7737                 if(this.browserEvent.type == 'mousedown'){
7738                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
7739                 }
7740                 E.stopEvent(this.browserEvent);
7741             }
7742         },
7743
7744         /**
7745          * Prevents the browsers default handling of the event.
7746          */
7747         preventDefault : function(){
7748             if(this.browserEvent){
7749                 E.preventDefault(this.browserEvent);
7750             }
7751         },
7752
7753         /** @private */
7754         isNavKeyPress : function(){
7755             var k = this.keyCode;
7756             k = Roo.isSafari ? (safariKeys[k] || k) : k;
7757             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
7758         },
7759
7760         isSpecialKey : function(){
7761             var k = this.keyCode;
7762             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
7763             (k == 16) || (k == 17) ||
7764             (k >= 18 && k <= 20) ||
7765             (k >= 33 && k <= 35) ||
7766             (k >= 36 && k <= 39) ||
7767             (k >= 44 && k <= 45);
7768         },
7769         /**
7770          * Cancels bubbling of the event.
7771          */
7772         stopPropagation : function(){
7773             if(this.browserEvent){
7774                 if(this.type == 'mousedown'){
7775                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
7776                 }
7777                 E.stopPropagation(this.browserEvent);
7778             }
7779         },
7780
7781         /**
7782          * Gets the key code for the event.
7783          * @return {Number}
7784          */
7785         getCharCode : function(){
7786             return this.charCode || this.keyCode;
7787         },
7788
7789         /**
7790          * Returns a normalized keyCode for the event.
7791          * @return {Number} The key code
7792          */
7793         getKey : function(){
7794             var k = this.keyCode || this.charCode;
7795             return Roo.isSafari ? (safariKeys[k] || k) : k;
7796         },
7797
7798         /**
7799          * Gets the x coordinate of the event.
7800          * @return {Number}
7801          */
7802         getPageX : function(){
7803             return this.xy[0];
7804         },
7805
7806         /**
7807          * Gets the y coordinate of the event.
7808          * @return {Number}
7809          */
7810         getPageY : function(){
7811             return this.xy[1];
7812         },
7813
7814         /**
7815          * Gets the time of the event.
7816          * @return {Number}
7817          */
7818         getTime : function(){
7819             if(this.browserEvent){
7820                 return E.getTime(this.browserEvent);
7821             }
7822             return null;
7823         },
7824
7825         /**
7826          * Gets the page coordinates of the event.
7827          * @return {Array} The xy values like [x, y]
7828          */
7829         getXY : function(){
7830             return this.xy;
7831         },
7832
7833         /**
7834          * Gets the target for the event.
7835          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
7836          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7837                 search as a number or element (defaults to 10 || document.body)
7838          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7839          * @return {HTMLelement}
7840          */
7841         getTarget : function(selector, maxDepth, returnEl){
7842             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
7843         },
7844         /**
7845          * Gets the related target.
7846          * @return {HTMLElement}
7847          */
7848         getRelatedTarget : function(){
7849             if(this.browserEvent){
7850                 return E.getRelatedTarget(this.browserEvent);
7851             }
7852             return null;
7853         },
7854
7855         /**
7856          * Normalizes mouse wheel delta across browsers
7857          * @return {Number} The delta
7858          */
7859         getWheelDelta : function(){
7860             var e = this.browserEvent;
7861             var delta = 0;
7862             if(e.wheelDelta){ /* IE/Opera. */
7863                 delta = e.wheelDelta/120;
7864             }else if(e.detail){ /* Mozilla case. */
7865                 delta = -e.detail/3;
7866             }
7867             return delta;
7868         },
7869
7870         /**
7871          * Returns true if the control, meta, shift or alt key was pressed during this event.
7872          * @return {Boolean}
7873          */
7874         hasModifier : function(){
7875             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
7876         },
7877
7878         /**
7879          * Returns true if the target of this event equals el or is a child of el
7880          * @param {String/HTMLElement/Element} el
7881          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
7882          * @return {Boolean}
7883          */
7884         within : function(el, related){
7885             var t = this[related ? "getRelatedTarget" : "getTarget"]();
7886             return t && Roo.fly(el).contains(t);
7887         },
7888
7889         getPoint : function(){
7890             return new Roo.lib.Point(this.xy[0], this.xy[1]);
7891         }
7892     };
7893
7894     return new Roo.EventObjectImpl();
7895 }();
7896             
7897     /*
7898  * Based on:
7899  * Ext JS Library 1.1.1
7900  * Copyright(c) 2006-2007, Ext JS, LLC.
7901  *
7902  * Originally Released Under LGPL - original licence link has changed is not relivant.
7903  *
7904  * Fork - LGPL
7905  * <script type="text/javascript">
7906  */
7907
7908  
7909 // was in Composite Element!??!?!
7910  
7911 (function(){
7912     var D = Roo.lib.Dom;
7913     var E = Roo.lib.Event;
7914     var A = Roo.lib.Anim;
7915
7916     // local style camelizing for speed
7917     var propCache = {};
7918     var camelRe = /(-[a-z])/gi;
7919     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
7920     var view = document.defaultView;
7921
7922 /**
7923  * @class Roo.Element
7924  * Represents an Element in the DOM.<br><br>
7925  * Usage:<br>
7926 <pre><code>
7927 var el = Roo.get("my-div");
7928
7929 // or with getEl
7930 var el = getEl("my-div");
7931
7932 // or with a DOM element
7933 var el = Roo.get(myDivElement);
7934 </code></pre>
7935  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
7936  * each call instead of constructing a new one.<br><br>
7937  * <b>Animations</b><br />
7938  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
7939  * should either be a boolean (true) or an object literal with animation options. The animation options are:
7940 <pre>
7941 Option    Default   Description
7942 --------- --------  ---------------------------------------------
7943 duration  .35       The duration of the animation in seconds
7944 easing    easeOut   The YUI easing method
7945 callback  none      A function to execute when the anim completes
7946 scope     this      The scope (this) of the callback function
7947 </pre>
7948 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
7949 * manipulate the animation. Here's an example:
7950 <pre><code>
7951 var el = Roo.get("my-div");
7952
7953 // no animation
7954 el.setWidth(100);
7955
7956 // default animation
7957 el.setWidth(100, true);
7958
7959 // animation with some options set
7960 el.setWidth(100, {
7961     duration: 1,
7962     callback: this.foo,
7963     scope: this
7964 });
7965
7966 // using the "anim" property to get the Anim object
7967 var opt = {
7968     duration: 1,
7969     callback: this.foo,
7970     scope: this
7971 };
7972 el.setWidth(100, opt);
7973 ...
7974 if(opt.anim.isAnimated()){
7975     opt.anim.stop();
7976 }
7977 </code></pre>
7978 * <b> Composite (Collections of) Elements</b><br />
7979  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
7980  * @constructor Create a new Element directly.
7981  * @param {String/HTMLElement} element
7982  * @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).
7983  */
7984     Roo.Element = function(element, forceNew)
7985     {
7986         var dom = typeof element == "string" ?
7987                 document.getElementById(element) : element;
7988         
7989         this.listeners = {};
7990         
7991         if(!dom){ // invalid id/element
7992             return null;
7993         }
7994         var id = dom.id;
7995         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7996             return Roo.Element.cache[id];
7997         }
7998
7999         /**
8000          * The DOM element
8001          * @type HTMLElement
8002          */
8003         this.dom = dom;
8004
8005         /**
8006          * The DOM element ID
8007          * @type String
8008          */
8009         this.id = id || Roo.id(dom);
8010         
8011         return this; // assumed for cctor?
8012     };
8013
8014     var El = Roo.Element;
8015
8016     El.prototype = {
8017         /**
8018          * The element's default display mode  (defaults to "") 
8019          * @type String
8020          */
8021         originalDisplay : "",
8022
8023         
8024         // note this is overridden in BS version..
8025         visibilityMode : 1, 
8026         /**
8027          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
8028          * @type String
8029          */
8030         defaultUnit : "px",
8031         
8032         /**
8033          * Sets the element's visibility mode. When setVisible() is called it
8034          * will use this to determine whether to set the visibility or the display property.
8035          * @param visMode Element.VISIBILITY or Element.DISPLAY
8036          * @return {Roo.Element} this
8037          */
8038         setVisibilityMode : function(visMode){
8039             this.visibilityMode = visMode;
8040             return this;
8041         },
8042         /**
8043          * Convenience method for setVisibilityMode(Element.DISPLAY)
8044          * @param {String} display (optional) What to set display to when visible
8045          * @return {Roo.Element} this
8046          */
8047         enableDisplayMode : function(display){
8048             this.setVisibilityMode(El.DISPLAY);
8049             if(typeof display != "undefined") { this.originalDisplay = display; }
8050             return this;
8051         },
8052
8053         /**
8054          * 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)
8055          * @param {String} selector The simple selector to test
8056          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8057                 search as a number or element (defaults to 10 || document.body)
8058          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
8059          * @return {HTMLElement} The matching DOM node (or null if no match was found)
8060          */
8061         findParent : function(simpleSelector, maxDepth, returnEl){
8062             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
8063             maxDepth = maxDepth || 50;
8064             if(typeof maxDepth != "number"){
8065                 stopEl = Roo.getDom(maxDepth);
8066                 maxDepth = 10;
8067             }
8068             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
8069                 if(dq.is(p, simpleSelector)){
8070                     return returnEl ? Roo.get(p) : p;
8071                 }
8072                 depth++;
8073                 p = p.parentNode;
8074             }
8075             return null;
8076         },
8077
8078
8079         /**
8080          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
8081          * @param {String} selector The simple selector to test
8082          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8083                 search as a number or element (defaults to 10 || document.body)
8084          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
8085          * @return {HTMLElement} The matching DOM node (or null if no match was found)
8086          */
8087         findParentNode : function(simpleSelector, maxDepth, returnEl){
8088             var p = Roo.fly(this.dom.parentNode, '_internal');
8089             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
8090         },
8091         
8092         /**
8093          * Looks at  the scrollable parent element
8094          */
8095         findScrollableParent : function()
8096         {
8097             var overflowRegex = /(auto|scroll)/;
8098             
8099             if(this.getStyle('position') === 'fixed'){
8100                 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
8101             }
8102             
8103             var excludeStaticParent = this.getStyle('position') === "absolute";
8104             
8105             for (var parent = this; (parent = Roo.get(parent.dom.parentNode));){
8106                 
8107                 if (excludeStaticParent && parent.getStyle('position') === "static") {
8108                     continue;
8109                 }
8110                 
8111                 if (overflowRegex.test(parent.getStyle('overflow') + parent.getStyle('overflow-x') + parent.getStyle('overflow-y'))){
8112                     return parent;
8113                 }
8114                 
8115                 if(parent.dom.nodeName.toLowerCase() == 'body'){
8116                     return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
8117                 }
8118             }
8119             
8120             return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
8121         },
8122
8123         /**
8124          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
8125          * This is a shortcut for findParentNode() that always returns an Roo.Element.
8126          * @param {String} selector The simple selector to test
8127          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8128                 search as a number or element (defaults to 10 || document.body)
8129          * @return {Roo.Element} The matching DOM node (or null if no match was found)
8130          */
8131         up : function(simpleSelector, maxDepth){
8132             return this.findParentNode(simpleSelector, maxDepth, true);
8133         },
8134
8135
8136
8137         /**
8138          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
8139          * @param {String} selector The simple selector to test
8140          * @return {Boolean} True if this element matches the selector, else false
8141          */
8142         is : function(simpleSelector){
8143             return Roo.DomQuery.is(this.dom, simpleSelector);
8144         },
8145
8146         /**
8147          * Perform animation on this element.
8148          * @param {Object} args The YUI animation control args
8149          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
8150          * @param {Function} onComplete (optional) Function to call when animation completes
8151          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
8152          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
8153          * @return {Roo.Element} this
8154          */
8155         animate : function(args, duration, onComplete, easing, animType){
8156             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
8157             return this;
8158         },
8159
8160         /*
8161          * @private Internal animation call
8162          */
8163         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
8164             animType = animType || 'run';
8165             opt = opt || {};
8166             var anim = Roo.lib.Anim[animType](
8167                 this.dom, args,
8168                 (opt.duration || defaultDur) || .35,
8169                 (opt.easing || defaultEase) || 'easeOut',
8170                 function(){
8171                     Roo.callback(cb, this);
8172                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
8173                 },
8174                 this
8175             );
8176             opt.anim = anim;
8177             return anim;
8178         },
8179
8180         // private legacy anim prep
8181         preanim : function(a, i){
8182             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
8183         },
8184
8185         /**
8186          * Removes worthless text nodes
8187          * @param {Boolean} forceReclean (optional) By default the element
8188          * keeps track if it has been cleaned already so
8189          * you can call this over and over. However, if you update the element and
8190          * need to force a reclean, you can pass true.
8191          */
8192         clean : function(forceReclean){
8193             if(this.isCleaned && forceReclean !== true){
8194                 return this;
8195             }
8196             var ns = /\S/;
8197             var d = this.dom, n = d.firstChild, ni = -1;
8198             while(n){
8199                 var nx = n.nextSibling;
8200                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
8201                     d.removeChild(n);
8202                 }else{
8203                     n.nodeIndex = ++ni;
8204                 }
8205                 n = nx;
8206             }
8207             this.isCleaned = true;
8208             return this;
8209         },
8210
8211         // private
8212         calcOffsetsTo : function(el){
8213             el = Roo.get(el);
8214             var d = el.dom;
8215             var restorePos = false;
8216             if(el.getStyle('position') == 'static'){
8217                 el.position('relative');
8218                 restorePos = true;
8219             }
8220             var x = 0, y =0;
8221             var op = this.dom;
8222             while(op && op != d && op.tagName != 'HTML'){
8223                 x+= op.offsetLeft;
8224                 y+= op.offsetTop;
8225                 op = op.offsetParent;
8226             }
8227             if(restorePos){
8228                 el.position('static');
8229             }
8230             return [x, y];
8231         },
8232
8233         /**
8234          * Scrolls this element into view within the passed container.
8235          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
8236          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
8237          * @return {Roo.Element} this
8238          */
8239         scrollIntoView : function(container, hscroll){
8240             var c = Roo.getDom(container) || document.body;
8241             var el = this.dom;
8242
8243             var o = this.calcOffsetsTo(c),
8244                 l = o[0],
8245                 t = o[1],
8246                 b = t+el.offsetHeight,
8247                 r = l+el.offsetWidth;
8248
8249             var ch = c.clientHeight;
8250             var ct = parseInt(c.scrollTop, 10);
8251             var cl = parseInt(c.scrollLeft, 10);
8252             var cb = ct + ch;
8253             var cr = cl + c.clientWidth;
8254
8255             if(t < ct){
8256                 c.scrollTop = t;
8257             }else if(b > cb){
8258                 c.scrollTop = b-ch;
8259             }
8260
8261             if(hscroll !== false){
8262                 if(l < cl){
8263                     c.scrollLeft = l;
8264                 }else if(r > cr){
8265                     c.scrollLeft = r-c.clientWidth;
8266                 }
8267             }
8268             return this;
8269         },
8270
8271         // private
8272         scrollChildIntoView : function(child, hscroll){
8273             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
8274         },
8275
8276         /**
8277          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
8278          * the new height may not be available immediately.
8279          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
8280          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
8281          * @param {Function} onComplete (optional) Function to call when animation completes
8282          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
8283          * @return {Roo.Element} this
8284          */
8285         autoHeight : function(animate, duration, onComplete, easing){
8286             var oldHeight = this.getHeight();
8287             this.clip();
8288             this.setHeight(1); // force clipping
8289             setTimeout(function(){
8290                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
8291                 if(!animate){
8292                     this.setHeight(height);
8293                     this.unclip();
8294                     if(typeof onComplete == "function"){
8295                         onComplete();
8296                     }
8297                 }else{
8298                     this.setHeight(oldHeight); // restore original height
8299                     this.setHeight(height, animate, duration, function(){
8300                         this.unclip();
8301                         if(typeof onComplete == "function") { onComplete(); }
8302                     }.createDelegate(this), easing);
8303                 }
8304             }.createDelegate(this), 0);
8305             return this;
8306         },
8307
8308         /**
8309          * Returns true if this element is an ancestor of the passed element
8310          * @param {HTMLElement/String} el The element to check
8311          * @return {Boolean} True if this element is an ancestor of el, else false
8312          */
8313         contains : function(el){
8314             if(!el){return false;}
8315             return D.isAncestor(this.dom, el.dom ? el.dom : el);
8316         },
8317
8318         /**
8319          * Checks whether the element is currently visible using both visibility and display properties.
8320          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
8321          * @return {Boolean} True if the element is currently visible, else false
8322          */
8323         isVisible : function(deep) {
8324             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
8325             if(deep !== true || !vis){
8326                 return vis;
8327             }
8328             var p = this.dom.parentNode;
8329             while(p && p.tagName.toLowerCase() != "body"){
8330                 if(!Roo.fly(p, '_isVisible').isVisible()){
8331                     return false;
8332                 }
8333                 p = p.parentNode;
8334             }
8335             return true;
8336         },
8337
8338         /**
8339          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
8340          * @param {String} selector The CSS selector
8341          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
8342          * @return {CompositeElement/CompositeElementLite} The composite element
8343          */
8344         select : function(selector, unique){
8345             return El.select(selector, unique, this.dom);
8346         },
8347
8348         /**
8349          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
8350          * @param {String} selector The CSS selector
8351          * @return {Array} An array of the matched nodes
8352          */
8353         query : function(selector, unique){
8354             return Roo.DomQuery.select(selector, this.dom);
8355         },
8356
8357         /**
8358          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
8359          * @param {String} selector The CSS selector
8360          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
8361          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
8362          */
8363         child : function(selector, returnDom){
8364             var n = Roo.DomQuery.selectNode(selector, this.dom);
8365             return returnDom ? n : Roo.get(n);
8366         },
8367
8368         /**
8369          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
8370          * @param {String} selector The CSS selector
8371          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
8372          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
8373          */
8374         down : function(selector, returnDom){
8375             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
8376             return returnDom ? n : Roo.get(n);
8377         },
8378
8379         /**
8380          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
8381          * @param {String} group The group the DD object is member of
8382          * @param {Object} config The DD config object
8383          * @param {Object} overrides An object containing methods to override/implement on the DD object
8384          * @return {Roo.dd.DD} The DD object
8385          */
8386         initDD : function(group, config, overrides){
8387             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
8388             return Roo.apply(dd, overrides);
8389         },
8390
8391         /**
8392          * Initializes a {@link Roo.dd.DDProxy} object for this element.
8393          * @param {String} group The group the DDProxy object is member of
8394          * @param {Object} config The DDProxy config object
8395          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
8396          * @return {Roo.dd.DDProxy} The DDProxy object
8397          */
8398         initDDProxy : function(group, config, overrides){
8399             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
8400             return Roo.apply(dd, overrides);
8401         },
8402
8403         /**
8404          * Initializes a {@link Roo.dd.DDTarget} object for this element.
8405          * @param {String} group The group the DDTarget object is member of
8406          * @param {Object} config The DDTarget config object
8407          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
8408          * @return {Roo.dd.DDTarget} The DDTarget object
8409          */
8410         initDDTarget : function(group, config, overrides){
8411             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
8412             return Roo.apply(dd, overrides);
8413         },
8414
8415         /**
8416          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
8417          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
8418          * @param {Boolean} visible Whether the element is visible
8419          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8420          * @return {Roo.Element} this
8421          */
8422          setVisible : function(visible, animate){
8423             if(!animate || !A){
8424                 if(this.visibilityMode == El.DISPLAY){
8425                     this.setDisplayed(visible);
8426                 }else{
8427                     this.fixDisplay();
8428                     this.dom.style.visibility = visible ? "visible" : "hidden";
8429                 }
8430             }else{
8431                 // closure for composites
8432                 var dom = this.dom;
8433                 var visMode = this.visibilityMode;
8434                 if(visible){
8435                     this.setOpacity(.01);
8436                     this.setVisible(true);
8437                 }
8438                 this.anim({opacity: { to: (visible?1:0) }},
8439                       this.preanim(arguments, 1),
8440                       null, .35, 'easeIn', function(){
8441                          if(!visible){
8442                              if(visMode == El.DISPLAY){
8443                                  dom.style.display = "none";
8444                              }else{
8445                                  dom.style.visibility = "hidden";
8446                              }
8447                              Roo.get(dom).setOpacity(1);
8448                          }
8449                      });
8450             }
8451             return this;
8452         },
8453
8454         /**
8455          * Returns true if display is not "none"
8456          * @return {Boolean}
8457          */
8458         isDisplayed : function() {
8459             return this.getStyle("display") != "none";
8460         },
8461
8462         /**
8463          * Toggles the element's visibility or display, depending on visibility mode.
8464          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8465          * @return {Roo.Element} this
8466          */
8467         toggle : function(animate){
8468             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
8469             return this;
8470         },
8471
8472         /**
8473          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
8474          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
8475          * @return {Roo.Element} this
8476          */
8477         setDisplayed : function(value) {
8478             if(typeof value == "boolean"){
8479                value = value ? this.originalDisplay : "none";
8480             }
8481             this.setStyle("display", value);
8482             return this;
8483         },
8484
8485         /**
8486          * Tries to focus the element. Any exceptions are caught and ignored.
8487          * @return {Roo.Element} this
8488          */
8489         focus : function() {
8490             try{
8491                 this.dom.focus();
8492             }catch(e){}
8493             return this;
8494         },
8495
8496         /**
8497          * Tries to blur the element. Any exceptions are caught and ignored.
8498          * @return {Roo.Element} this
8499          */
8500         blur : function() {
8501             try{
8502                 this.dom.blur();
8503             }catch(e){}
8504             return this;
8505         },
8506
8507         /**
8508          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
8509          * @param {String/Array} className The CSS class to add, or an array of classes
8510          * @return {Roo.Element} this
8511          */
8512         addClass : function(className){
8513             if(className instanceof Array){
8514                 for(var i = 0, len = className.length; i < len; i++) {
8515                     this.addClass(className[i]);
8516                 }
8517             }else{
8518                 if(className && !this.hasClass(className)){
8519                     if (this.dom instanceof SVGElement) {
8520                         this.dom.className.baseVal =this.dom.className.baseVal  + " " + className;
8521                     } else {
8522                         this.dom.className = this.dom.className + " " + className;
8523                     }
8524                 }
8525             }
8526             return this;
8527         },
8528
8529         /**
8530          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
8531          * @param {String/Array} className The CSS class to add, or an array of classes
8532          * @return {Roo.Element} this
8533          */
8534         radioClass : function(className){
8535             var siblings = this.dom.parentNode.childNodes;
8536             for(var i = 0; i < siblings.length; i++) {
8537                 var s = siblings[i];
8538                 if(s.nodeType == 1){
8539                     Roo.get(s).removeClass(className);
8540                 }
8541             }
8542             this.addClass(className);
8543             return this;
8544         },
8545
8546         /**
8547          * Removes one or more CSS classes from the element.
8548          * @param {String/Array} className The CSS class to remove, or an array of classes
8549          * @return {Roo.Element} this
8550          */
8551         removeClass : function(className){
8552             
8553             var cn = this.dom instanceof SVGElement ? this.dom.className.baseVal : this.dom.className;
8554             if(!className || !cn){
8555                 return this;
8556             }
8557             if(className instanceof Array){
8558                 for(var i = 0, len = className.length; i < len; i++) {
8559                     this.removeClass(className[i]);
8560                 }
8561             }else{
8562                 if(this.hasClass(className)){
8563                     var re = this.classReCache[className];
8564                     if (!re) {
8565                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
8566                        this.classReCache[className] = re;
8567                     }
8568                     if (this.dom instanceof SVGElement) {
8569                         this.dom.className.baseVal = cn.replace(re, " ");
8570                     } else {
8571                         this.dom.className = cn.replace(re, " ");
8572                     }
8573                 }
8574             }
8575             return this;
8576         },
8577
8578         // private
8579         classReCache: {},
8580
8581         /**
8582          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
8583          * @param {String} className The CSS class to toggle
8584          * @return {Roo.Element} this
8585          */
8586         toggleClass : function(className){
8587             if(this.hasClass(className)){
8588                 this.removeClass(className);
8589             }else{
8590                 this.addClass(className);
8591             }
8592             return this;
8593         },
8594
8595         /**
8596          * Checks if the specified CSS class exists on this element's DOM node.
8597          * @param {String} className The CSS class to check for
8598          * @return {Boolean} True if the class exists, else false
8599          */
8600         hasClass : function(className){
8601             if (this.dom instanceof SVGElement) {
8602                 return className && (' '+this.dom.className.baseVal +' ').indexOf(' '+className+' ') != -1; 
8603             } 
8604             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
8605         },
8606
8607         /**
8608          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
8609          * @param {String} oldClassName The CSS class to replace
8610          * @param {String} newClassName The replacement CSS class
8611          * @return {Roo.Element} this
8612          */
8613         replaceClass : function(oldClassName, newClassName){
8614             this.removeClass(oldClassName);
8615             this.addClass(newClassName);
8616             return this;
8617         },
8618
8619         /**
8620          * Returns an object with properties matching the styles requested.
8621          * For example, el.getStyles('color', 'font-size', 'width') might return
8622          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
8623          * @param {String} style1 A style name
8624          * @param {String} style2 A style name
8625          * @param {String} etc.
8626          * @return {Object} The style object
8627          */
8628         getStyles : function(){
8629             var a = arguments, len = a.length, r = {};
8630             for(var i = 0; i < len; i++){
8631                 r[a[i]] = this.getStyle(a[i]);
8632             }
8633             return r;
8634         },
8635
8636         /**
8637          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
8638          * @param {String} property The style property whose value is returned.
8639          * @return {String} The current value of the style property for this element.
8640          */
8641         getStyle : function(){
8642             return view && view.getComputedStyle ?
8643                 function(prop){
8644                     var el = this.dom, v, cs, camel;
8645                     if(prop == 'float'){
8646                         prop = "cssFloat";
8647                     }
8648                     if(el.style && (v = el.style[prop])){
8649                         return v;
8650                     }
8651                     if(cs = view.getComputedStyle(el, "")){
8652                         if(!(camel = propCache[prop])){
8653                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
8654                         }
8655                         return cs[camel];
8656                     }
8657                     return null;
8658                 } :
8659                 function(prop){
8660                     var el = this.dom, v, cs, camel;
8661                     if(prop == 'opacity'){
8662                         if(typeof el.style.filter == 'string'){
8663                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
8664                             if(m){
8665                                 var fv = parseFloat(m[1]);
8666                                 if(!isNaN(fv)){
8667                                     return fv ? fv / 100 : 0;
8668                                 }
8669                             }
8670                         }
8671                         return 1;
8672                     }else if(prop == 'float'){
8673                         prop = "styleFloat";
8674                     }
8675                     if(!(camel = propCache[prop])){
8676                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
8677                     }
8678                     if(v = el.style[camel]){
8679                         return v;
8680                     }
8681                     if(cs = el.currentStyle){
8682                         return cs[camel];
8683                     }
8684                     return null;
8685                 };
8686         }(),
8687
8688         /**
8689          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
8690          * @param {String/Object} property The style property to be set, or an object of multiple styles.
8691          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
8692          * @return {Roo.Element} this
8693          */
8694         setStyle : function(prop, value){
8695             if(typeof prop == "string"){
8696                 
8697                 if (prop == 'float') {
8698                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
8699                     return this;
8700                 }
8701                 
8702                 var camel;
8703                 if(!(camel = propCache[prop])){
8704                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
8705                 }
8706                 
8707                 if(camel == 'opacity') {
8708                     this.setOpacity(value);
8709                 }else{
8710                     this.dom.style[camel] = value;
8711                 }
8712             }else{
8713                 for(var style in prop){
8714                     if(typeof prop[style] != "function"){
8715                        this.setStyle(style, prop[style]);
8716                     }
8717                 }
8718             }
8719             return this;
8720         },
8721
8722         /**
8723          * More flexible version of {@link #setStyle} for setting style properties.
8724          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
8725          * a function which returns such a specification.
8726          * @return {Roo.Element} this
8727          */
8728         applyStyles : function(style){
8729             Roo.DomHelper.applyStyles(this.dom, style);
8730             return this;
8731         },
8732
8733         /**
8734           * 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).
8735           * @return {Number} The X position of the element
8736           */
8737         getX : function(){
8738             return D.getX(this.dom);
8739         },
8740
8741         /**
8742           * 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).
8743           * @return {Number} The Y position of the element
8744           */
8745         getY : function(){
8746             return D.getY(this.dom);
8747         },
8748
8749         /**
8750           * 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).
8751           * @return {Array} The XY position of the element
8752           */
8753         getXY : function(){
8754             return D.getXY(this.dom);
8755         },
8756
8757         /**
8758          * 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).
8759          * @param {Number} The X position of the element
8760          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8761          * @return {Roo.Element} this
8762          */
8763         setX : function(x, animate){
8764             if(!animate || !A){
8765                 D.setX(this.dom, x);
8766             }else{
8767                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
8768             }
8769             return this;
8770         },
8771
8772         /**
8773          * 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).
8774          * @param {Number} The Y position of the element
8775          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8776          * @return {Roo.Element} this
8777          */
8778         setY : function(y, animate){
8779             if(!animate || !A){
8780                 D.setY(this.dom, y);
8781             }else{
8782                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
8783             }
8784             return this;
8785         },
8786
8787         /**
8788          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
8789          * @param {String} left The left CSS property value
8790          * @return {Roo.Element} this
8791          */
8792         setLeft : function(left){
8793             this.setStyle("left", this.addUnits(left));
8794             return this;
8795         },
8796
8797         /**
8798          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
8799          * @param {String} top The top CSS property value
8800          * @return {Roo.Element} this
8801          */
8802         setTop : function(top){
8803             this.setStyle("top", this.addUnits(top));
8804             return this;
8805         },
8806
8807         /**
8808          * Sets the element's CSS right style.
8809          * @param {String} right The right CSS property value
8810          * @return {Roo.Element} this
8811          */
8812         setRight : function(right){
8813             this.setStyle("right", this.addUnits(right));
8814             return this;
8815         },
8816
8817         /**
8818          * Sets the element's CSS bottom style.
8819          * @param {String} bottom The bottom CSS property value
8820          * @return {Roo.Element} this
8821          */
8822         setBottom : function(bottom){
8823             this.setStyle("bottom", this.addUnits(bottom));
8824             return this;
8825         },
8826
8827         /**
8828          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
8829          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
8830          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
8831          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8832          * @return {Roo.Element} this
8833          */
8834         setXY : function(pos, animate){
8835             if(!animate || !A){
8836                 D.setXY(this.dom, pos);
8837             }else{
8838                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
8839             }
8840             return this;
8841         },
8842
8843         /**
8844          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
8845          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
8846          * @param {Number} x X value for new position (coordinates are page-based)
8847          * @param {Number} y Y value for new position (coordinates are page-based)
8848          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8849          * @return {Roo.Element} this
8850          */
8851         setLocation : function(x, y, animate){
8852             this.setXY([x, y], this.preanim(arguments, 2));
8853             return this;
8854         },
8855
8856         /**
8857          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
8858          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
8859          * @param {Number} x X value for new position (coordinates are page-based)
8860          * @param {Number} y Y value for new position (coordinates are page-based)
8861          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8862          * @return {Roo.Element} this
8863          */
8864         moveTo : function(x, y, animate){
8865             this.setXY([x, y], this.preanim(arguments, 2));
8866             return this;
8867         },
8868
8869         /**
8870          * Returns the region of the given element.
8871          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
8872          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
8873          */
8874         getRegion : function(){
8875             return D.getRegion(this.dom);
8876         },
8877
8878         /**
8879          * Returns the offset height of the element
8880          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
8881          * @return {Number} The element's height
8882          */
8883         getHeight : function(contentHeight){
8884             var h = this.dom.offsetHeight || 0;
8885             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
8886         },
8887
8888         /**
8889          * Returns the offset width of the element
8890          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
8891          * @return {Number} The element's width
8892          */
8893         getWidth : function(contentWidth){
8894             var w = this.dom.offsetWidth || 0;
8895             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
8896         },
8897
8898         /**
8899          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
8900          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
8901          * if a height has not been set using CSS.
8902          * @return {Number}
8903          */
8904         getComputedHeight : function(){
8905             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
8906             if(!h){
8907                 h = parseInt(this.getStyle('height'), 10) || 0;
8908                 if(!this.isBorderBox()){
8909                     h += this.getFrameWidth('tb');
8910                 }
8911             }
8912             return h;
8913         },
8914
8915         /**
8916          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
8917          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
8918          * if a width has not been set using CSS.
8919          * @return {Number}
8920          */
8921         getComputedWidth : function(){
8922             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
8923             if(!w){
8924                 w = parseInt(this.getStyle('width'), 10) || 0;
8925                 if(!this.isBorderBox()){
8926                     w += this.getFrameWidth('lr');
8927                 }
8928             }
8929             return w;
8930         },
8931
8932         /**
8933          * Returns the size of the element.
8934          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
8935          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
8936          */
8937         getSize : function(contentSize){
8938             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
8939         },
8940
8941         /**
8942          * Returns the width and height of the viewport.
8943          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
8944          */
8945         getViewSize : function(){
8946             var d = this.dom, doc = document, aw = 0, ah = 0;
8947             if(d == doc || d == doc.body){
8948                 return {width : D.getViewWidth(), height: D.getViewHeight()};
8949             }else{
8950                 return {
8951                     width : d.clientWidth,
8952                     height: d.clientHeight
8953                 };
8954             }
8955         },
8956
8957         /**
8958          * Returns the value of the "value" attribute
8959          * @param {Boolean} asNumber true to parse the value as a number
8960          * @return {String/Number}
8961          */
8962         getValue : function(asNumber){
8963             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
8964         },
8965
8966         // private
8967         adjustWidth : function(width){
8968             if(typeof width == "number"){
8969                 if(this.autoBoxAdjust && !this.isBorderBox()){
8970                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8971                 }
8972                 if(width < 0){
8973                     width = 0;
8974                 }
8975             }
8976             return width;
8977         },
8978
8979         // private
8980         adjustHeight : function(height){
8981             if(typeof height == "number"){
8982                if(this.autoBoxAdjust && !this.isBorderBox()){
8983                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8984                }
8985                if(height < 0){
8986                    height = 0;
8987                }
8988             }
8989             return height;
8990         },
8991
8992         /**
8993          * Set the width of the element
8994          * @param {Number} width The new width
8995          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8996          * @return {Roo.Element} this
8997          */
8998         setWidth : function(width, animate){
8999             width = this.adjustWidth(width);
9000             if(!animate || !A){
9001                 this.dom.style.width = this.addUnits(width);
9002             }else{
9003                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
9004             }
9005             return this;
9006         },
9007
9008         /**
9009          * Set the height of the element
9010          * @param {Number} height The new height
9011          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9012          * @return {Roo.Element} this
9013          */
9014          setHeight : function(height, animate){
9015             height = this.adjustHeight(height);
9016             if(!animate || !A){
9017                 this.dom.style.height = this.addUnits(height);
9018             }else{
9019                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
9020             }
9021             return this;
9022         },
9023
9024         /**
9025          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
9026          * @param {Number} width The new width
9027          * @param {Number} height The new height
9028          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9029          * @return {Roo.Element} this
9030          */
9031          setSize : function(width, height, animate){
9032             if(typeof width == "object"){ // in case of object from getSize()
9033                 height = width.height; width = width.width;
9034             }
9035             width = this.adjustWidth(width); height = this.adjustHeight(height);
9036             if(!animate || !A){
9037                 this.dom.style.width = this.addUnits(width);
9038                 this.dom.style.height = this.addUnits(height);
9039             }else{
9040                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
9041             }
9042             return this;
9043         },
9044
9045         /**
9046          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
9047          * @param {Number} x X value for new position (coordinates are page-based)
9048          * @param {Number} y Y value for new position (coordinates are page-based)
9049          * @param {Number} width The new width
9050          * @param {Number} height The new height
9051          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9052          * @return {Roo.Element} this
9053          */
9054         setBounds : function(x, y, width, height, animate){
9055             if(!animate || !A){
9056                 this.setSize(width, height);
9057                 this.setLocation(x, y);
9058             }else{
9059                 width = this.adjustWidth(width); height = this.adjustHeight(height);
9060                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
9061                               this.preanim(arguments, 4), 'motion');
9062             }
9063             return this;
9064         },
9065
9066         /**
9067          * 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.
9068          * @param {Roo.lib.Region} region The region to fill
9069          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9070          * @return {Roo.Element} this
9071          */
9072         setRegion : function(region, animate){
9073             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
9074             return this;
9075         },
9076
9077         /**
9078          * Appends an event handler
9079          *
9080          * @param {String}   eventName     The type of event to append
9081          * @param {Function} fn        The method the event invokes
9082          * @param {Object} scope       (optional) The scope (this object) of the fn
9083          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9084          */
9085         addListener : function(eventName, fn, scope, options)
9086         {
9087             if (eventName == 'dblclick') { // doublclick (touchstart) - faked on touch.
9088                 this.addListener('touchstart', this.onTapHandler, this);
9089             }
9090             
9091             // we need to handle a special case where dom element is a svg element.
9092             // in this case we do not actua
9093             if (!this.dom) {
9094                 return;
9095             }
9096             
9097             if (this.dom instanceof SVGElement && !(this.dom instanceof SVGSVGElement)) {
9098                 if (typeof(this.listeners[eventName]) == 'undefined') {
9099                     this.listeners[eventName] =  new Roo.util.Event(this, eventName);
9100                 }
9101                 this.listeners[eventName].addListener(fn, scope, options);
9102                 return;
9103             }
9104             
9105                 
9106             Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
9107             
9108             
9109         },
9110         tapedTwice : false,
9111         onTapHandler : function(event)
9112         {
9113             if(!this.tapedTwice) {
9114                 this.tapedTwice = true;
9115                 var s = this;
9116                 setTimeout( function() {
9117                     s.tapedTwice = false;
9118                 }, 300 );
9119                 return;
9120             }
9121             event.preventDefault();
9122             var revent = new MouseEvent('dblclick',  {
9123                 view: window,
9124                 bubbles: true,
9125                 cancelable: true
9126             });
9127              
9128             this.dom.dispatchEvent(revent);
9129             //action on double tap goes below
9130              
9131         }, 
9132  
9133         /**
9134          * Removes an event handler from this element
9135          * @param {String} eventName the type of event to remove
9136          * @param {Function} fn the method the event invokes
9137          * @param {Function} scope (needed for svg fake listeners)
9138          * @return {Roo.Element} this
9139          */
9140         removeListener : function(eventName, fn, scope){
9141             Roo.EventManager.removeListener(this.dom,  eventName, fn);
9142             if (typeof(this.listeners) == 'undefined'  || typeof(this.listeners[eventName]) == 'undefined') {
9143                 return this;
9144             }
9145             this.listeners[eventName].removeListener(fn, scope);
9146             return this;
9147         },
9148
9149         /**
9150          * Removes all previous added listeners from this element
9151          * @return {Roo.Element} this
9152          */
9153         removeAllListeners : function(){
9154             E.purgeElement(this.dom);
9155             this.listeners = {};
9156             return this;
9157         },
9158
9159         relayEvent : function(eventName, observable){
9160             this.on(eventName, function(e){
9161                 observable.fireEvent(eventName, e);
9162             });
9163         },
9164
9165         
9166         /**
9167          * Set the opacity of the element
9168          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
9169          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9170          * @return {Roo.Element} this
9171          */
9172          setOpacity : function(opacity, animate){
9173             if(!animate || !A){
9174                 var s = this.dom.style;
9175                 if(Roo.isIE){
9176                     s.zoom = 1;
9177                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
9178                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
9179                 }else{
9180                     s.opacity = opacity;
9181                 }
9182             }else{
9183                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
9184             }
9185             return this;
9186         },
9187
9188         /**
9189          * Gets the left X coordinate
9190          * @param {Boolean} local True to get the local css position instead of page coordinate
9191          * @return {Number}
9192          */
9193         getLeft : function(local){
9194             if(!local){
9195                 return this.getX();
9196             }else{
9197                 return parseInt(this.getStyle("left"), 10) || 0;
9198             }
9199         },
9200
9201         /**
9202          * Gets the right X coordinate of the element (element X position + element width)
9203          * @param {Boolean} local True to get the local css position instead of page coordinate
9204          * @return {Number}
9205          */
9206         getRight : function(local){
9207             if(!local){
9208                 return this.getX() + this.getWidth();
9209             }else{
9210                 return (this.getLeft(true) + this.getWidth()) || 0;
9211             }
9212         },
9213
9214         /**
9215          * Gets the top Y coordinate
9216          * @param {Boolean} local True to get the local css position instead of page coordinate
9217          * @return {Number}
9218          */
9219         getTop : function(local) {
9220             if(!local){
9221                 return this.getY();
9222             }else{
9223                 return parseInt(this.getStyle("top"), 10) || 0;
9224             }
9225         },
9226
9227         /**
9228          * Gets the bottom Y coordinate of the element (element Y position + element height)
9229          * @param {Boolean} local True to get the local css position instead of page coordinate
9230          * @return {Number}
9231          */
9232         getBottom : function(local){
9233             if(!local){
9234                 return this.getY() + this.getHeight();
9235             }else{
9236                 return (this.getTop(true) + this.getHeight()) || 0;
9237             }
9238         },
9239
9240         /**
9241         * Initializes positioning on this element. If a desired position is not passed, it will make the
9242         * the element positioned relative IF it is not already positioned.
9243         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
9244         * @param {Number} zIndex (optional) The zIndex to apply
9245         * @param {Number} x (optional) Set the page X position
9246         * @param {Number} y (optional) Set the page Y position
9247         */
9248         position : function(pos, zIndex, x, y){
9249             if(!pos){
9250                if(this.getStyle('position') == 'static'){
9251                    this.setStyle('position', 'relative');
9252                }
9253             }else{
9254                 this.setStyle("position", pos);
9255             }
9256             if(zIndex){
9257                 this.setStyle("z-index", zIndex);
9258             }
9259             if(x !== undefined && y !== undefined){
9260                 this.setXY([x, y]);
9261             }else if(x !== undefined){
9262                 this.setX(x);
9263             }else if(y !== undefined){
9264                 this.setY(y);
9265             }
9266         },
9267
9268         /**
9269         * Clear positioning back to the default when the document was loaded
9270         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
9271         * @return {Roo.Element} this
9272          */
9273         clearPositioning : function(value){
9274             value = value ||'';
9275             this.setStyle({
9276                 "left": value,
9277                 "right": value,
9278                 "top": value,
9279                 "bottom": value,
9280                 "z-index": "",
9281                 "position" : "static"
9282             });
9283             return this;
9284         },
9285
9286         /**
9287         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
9288         * snapshot before performing an update and then restoring the element.
9289         * @return {Object}
9290         */
9291         getPositioning : function(){
9292             var l = this.getStyle("left");
9293             var t = this.getStyle("top");
9294             return {
9295                 "position" : this.getStyle("position"),
9296                 "left" : l,
9297                 "right" : l ? "" : this.getStyle("right"),
9298                 "top" : t,
9299                 "bottom" : t ? "" : this.getStyle("bottom"),
9300                 "z-index" : this.getStyle("z-index")
9301             };
9302         },
9303
9304         /**
9305          * Gets the width of the border(s) for the specified side(s)
9306          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
9307          * passing lr would get the border (l)eft width + the border (r)ight width.
9308          * @return {Number} The width of the sides passed added together
9309          */
9310         getBorderWidth : function(side){
9311             return this.addStyles(side, El.borders);
9312         },
9313
9314         /**
9315          * Gets the width of the padding(s) for the specified side(s)
9316          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
9317          * passing lr would get the padding (l)eft + the padding (r)ight.
9318          * @return {Number} The padding of the sides passed added together
9319          */
9320         getPadding : function(side){
9321             return this.addStyles(side, El.paddings);
9322         },
9323
9324         /**
9325         * Set positioning with an object returned by getPositioning().
9326         * @param {Object} posCfg
9327         * @return {Roo.Element} this
9328          */
9329         setPositioning : function(pc){
9330             this.applyStyles(pc);
9331             if(pc.right == "auto"){
9332                 this.dom.style.right = "";
9333             }
9334             if(pc.bottom == "auto"){
9335                 this.dom.style.bottom = "";
9336             }
9337             return this;
9338         },
9339
9340         // private
9341         fixDisplay : function(){
9342             if(this.getStyle("display") == "none"){
9343                 this.setStyle("visibility", "hidden");
9344                 this.setStyle("display", this.originalDisplay); // first try reverting to default
9345                 if(this.getStyle("display") == "none"){ // if that fails, default to block
9346                     this.setStyle("display", "block");
9347                 }
9348             }
9349         },
9350
9351         /**
9352          * Quick set left and top adding default units
9353          * @param {String} left The left CSS property value
9354          * @param {String} top The top CSS property value
9355          * @return {Roo.Element} this
9356          */
9357          setLeftTop : function(left, top){
9358             this.dom.style.left = this.addUnits(left);
9359             this.dom.style.top = this.addUnits(top);
9360             return this;
9361         },
9362
9363         /**
9364          * Move this element relative to its current position.
9365          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9366          * @param {Number} distance How far to move the element in pixels
9367          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9368          * @return {Roo.Element} this
9369          */
9370          move : function(direction, distance, animate){
9371             var xy = this.getXY();
9372             direction = direction.toLowerCase();
9373             switch(direction){
9374                 case "l":
9375                 case "left":
9376                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
9377                     break;
9378                case "r":
9379                case "right":
9380                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
9381                     break;
9382                case "t":
9383                case "top":
9384                case "up":
9385                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
9386                     break;
9387                case "b":
9388                case "bottom":
9389                case "down":
9390                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
9391                     break;
9392             }
9393             return this;
9394         },
9395
9396         /**
9397          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
9398          * @return {Roo.Element} this
9399          */
9400         clip : function(){
9401             if(!this.isClipped){
9402                this.isClipped = true;
9403                this.originalClip = {
9404                    "o": this.getStyle("overflow"),
9405                    "x": this.getStyle("overflow-x"),
9406                    "y": this.getStyle("overflow-y")
9407                };
9408                this.setStyle("overflow", "hidden");
9409                this.setStyle("overflow-x", "hidden");
9410                this.setStyle("overflow-y", "hidden");
9411             }
9412             return this;
9413         },
9414
9415         /**
9416          *  Return clipping (overflow) to original clipping before clip() was called
9417          * @return {Roo.Element} this
9418          */
9419         unclip : function(){
9420             if(this.isClipped){
9421                 this.isClipped = false;
9422                 var o = this.originalClip;
9423                 if(o.o){this.setStyle("overflow", o.o);}
9424                 if(o.x){this.setStyle("overflow-x", o.x);}
9425                 if(o.y){this.setStyle("overflow-y", o.y);}
9426             }
9427             return this;
9428         },
9429
9430
9431         /**
9432          * Gets the x,y coordinates specified by the anchor position on the element.
9433          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
9434          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
9435          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
9436          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
9437          * @return {Array} [x, y] An array containing the element's x and y coordinates
9438          */
9439         getAnchorXY : function(anchor, local, s){
9440             //Passing a different size is useful for pre-calculating anchors,
9441             //especially for anchored animations that change the el size.
9442
9443             var w, h, vp = false;
9444             if(!s){
9445                 var d = this.dom;
9446                 if(d == document.body || d == document){
9447                     vp = true;
9448                     w = D.getViewWidth(); h = D.getViewHeight();
9449                 }else{
9450                     w = this.getWidth(); h = this.getHeight();
9451                 }
9452             }else{
9453                 w = s.width;  h = s.height;
9454             }
9455             var x = 0, y = 0, r = Math.round;
9456             switch((anchor || "tl").toLowerCase()){
9457                 case "c":
9458                     x = r(w*.5);
9459                     y = r(h*.5);
9460                 break;
9461                 case "t":
9462                     x = r(w*.5);
9463                     y = 0;
9464                 break;
9465                 case "l":
9466                     x = 0;
9467                     y = r(h*.5);
9468                 break;
9469                 case "r":
9470                     x = w;
9471                     y = r(h*.5);
9472                 break;
9473                 case "b":
9474                     x = r(w*.5);
9475                     y = h;
9476                 break;
9477                 case "tl":
9478                     x = 0;
9479                     y = 0;
9480                 break;
9481                 case "bl":
9482                     x = 0;
9483                     y = h;
9484                 break;
9485                 case "br":
9486                     x = w;
9487                     y = h;
9488                 break;
9489                 case "tr":
9490                     x = w;
9491                     y = 0;
9492                 break;
9493             }
9494             if(local === true){
9495                 return [x, y];
9496             }
9497             if(vp){
9498                 var sc = this.getScroll();
9499                 return [x + sc.left, y + sc.top];
9500             }
9501             //Add the element's offset xy
9502             var o = this.getXY();
9503             return [x+o[0], y+o[1]];
9504         },
9505
9506         /**
9507          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
9508          * supported position values.
9509          * @param {String/HTMLElement/Roo.Element} element The element to align to.
9510          * @param {String} position The position to align to.
9511          * @param {Array} offsets (optional) Offset the positioning by [x, y]
9512          * @return {Array} [x, y]
9513          */
9514         getAlignToXY : function(el, p, o)
9515         {
9516             el = Roo.get(el);
9517             var d = this.dom;
9518             if(!el.dom){
9519                 throw "Element.alignTo with an element that doesn't exist";
9520             }
9521             var c = false; //constrain to viewport
9522             var p1 = "", p2 = "";
9523             o = o || [0,0];
9524
9525             if(!p){
9526                 p = "tl-bl";
9527             }else if(p == "?"){
9528                 p = "tl-bl?";
9529             }else if(p.indexOf("-") == -1){
9530                 p = "tl-" + p;
9531             }
9532             p = p.toLowerCase();
9533             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
9534             if(!m){
9535                throw "Element.alignTo with an invalid alignment " + p;
9536             }
9537             p1 = m[1]; p2 = m[2]; c = !!m[3];
9538
9539             //Subtract the aligned el's internal xy from the target's offset xy
9540             //plus custom offset to get the aligned el's new offset xy
9541             var a1 = this.getAnchorXY(p1, true);
9542             var a2 = el.getAnchorXY(p2, false);
9543             var x = a2[0] - a1[0] + o[0];
9544             var y = a2[1] - a1[1] + o[1];
9545             if(c){
9546                 //constrain the aligned el to viewport if necessary
9547                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
9548                 // 5px of margin for ie
9549                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
9550
9551                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
9552                 //perpendicular to the vp border, allow the aligned el to slide on that border,
9553                 //otherwise swap the aligned el to the opposite border of the target.
9554                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
9555                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
9556                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t")  );
9557                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
9558
9559                var doc = document;
9560                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
9561                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
9562
9563                if((x+w) > dw + scrollX){
9564                     x = swapX ? r.left-w : dw+scrollX-w;
9565                 }
9566                if(x < scrollX){
9567                    x = swapX ? r.right : scrollX;
9568                }
9569                if((y+h) > dh + scrollY){
9570                     y = swapY ? r.top-h : dh+scrollY-h;
9571                 }
9572                if (y < scrollY){
9573                    y = swapY ? r.bottom : scrollY;
9574                }
9575             }
9576             return [x,y];
9577         },
9578
9579         // private
9580         getConstrainToXY : function(){
9581             var os = {top:0, left:0, bottom:0, right: 0};
9582
9583             return function(el, local, offsets, proposedXY){
9584                 el = Roo.get(el);
9585                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
9586
9587                 var vw, vh, vx = 0, vy = 0;
9588                 if(el.dom == document.body || el.dom == document){
9589                     vw = Roo.lib.Dom.getViewWidth();
9590                     vh = Roo.lib.Dom.getViewHeight();
9591                 }else{
9592                     vw = el.dom.clientWidth;
9593                     vh = el.dom.clientHeight;
9594                     if(!local){
9595                         var vxy = el.getXY();
9596                         vx = vxy[0];
9597                         vy = vxy[1];
9598                     }
9599                 }
9600
9601                 var s = el.getScroll();
9602
9603                 vx += offsets.left + s.left;
9604                 vy += offsets.top + s.top;
9605
9606                 vw -= offsets.right;
9607                 vh -= offsets.bottom;
9608
9609                 var vr = vx+vw;
9610                 var vb = vy+vh;
9611
9612                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
9613                 var x = xy[0], y = xy[1];
9614                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
9615
9616                 // only move it if it needs it
9617                 var moved = false;
9618
9619                 // first validate right/bottom
9620                 if((x + w) > vr){
9621                     x = vr - w;
9622                     moved = true;
9623                 }
9624                 if((y + h) > vb){
9625                     y = vb - h;
9626                     moved = true;
9627                 }
9628                 // then make sure top/left isn't negative
9629                 if(x < vx){
9630                     x = vx;
9631                     moved = true;
9632                 }
9633                 if(y < vy){
9634                     y = vy;
9635                     moved = true;
9636                 }
9637                 return moved ? [x, y] : false;
9638             };
9639         }(),
9640
9641         // private
9642         adjustForConstraints : function(xy, parent, offsets){
9643             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
9644         },
9645
9646         /**
9647          * Aligns this element with another element relative to the specified anchor points. If the other element is the
9648          * document it aligns it to the viewport.
9649          * The position parameter is optional, and can be specified in any one of the following formats:
9650          * <ul>
9651          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
9652          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
9653          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
9654          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
9655          *   <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
9656          *       element's anchor point, and the second value is used as the target's anchor point.</li>
9657          * </ul>
9658          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
9659          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
9660          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
9661          * that specified in order to enforce the viewport constraints.
9662          * Following are all of the supported anchor positions:
9663     <pre>
9664     Value  Description
9665     -----  -----------------------------
9666     tl     The top left corner (default)
9667     t      The center of the top edge
9668     tr     The top right corner
9669     l      The center of the left edge
9670     c      In the center of the element
9671     r      The center of the right edge
9672     bl     The bottom left corner
9673     b      The center of the bottom edge
9674     br     The bottom right corner
9675     </pre>
9676     Example Usage:
9677     <pre><code>
9678     // align el to other-el using the default positioning ("tl-bl", non-constrained)
9679     el.alignTo("other-el");
9680
9681     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
9682     el.alignTo("other-el", "tr?");
9683
9684     // align the bottom right corner of el with the center left edge of other-el
9685     el.alignTo("other-el", "br-l?");
9686
9687     // align the center of el with the bottom left corner of other-el and
9688     // adjust the x position by -6 pixels (and the y position by 0)
9689     el.alignTo("other-el", "c-bl", [-6, 0]);
9690     </code></pre>
9691          * @param {String/HTMLElement/Roo.Element} element The element to align to.
9692          * @param {String} position The position to align to.
9693          * @param {Array} offsets (optional) Offset the positioning by [x, y]
9694          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9695          * @return {Roo.Element} this
9696          */
9697         alignTo : function(element, position, offsets, animate){
9698             var xy = this.getAlignToXY(element, position, offsets);
9699             this.setXY(xy, this.preanim(arguments, 3));
9700             return this;
9701         },
9702
9703         /**
9704          * Anchors an element to another element and realigns it when the window is resized.
9705          * @param {String/HTMLElement/Roo.Element} element The element to align to.
9706          * @param {String} position The position to align to.
9707          * @param {Array} offsets (optional) Offset the positioning by [x, y]
9708          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
9709          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
9710          * is a number, it is used as the buffer delay (defaults to 50ms).
9711          * @param {Function} callback The function to call after the animation finishes
9712          * @return {Roo.Element} this
9713          */
9714         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
9715             var action = function(){
9716                 this.alignTo(el, alignment, offsets, animate);
9717                 Roo.callback(callback, this);
9718             };
9719             Roo.EventManager.onWindowResize(action, this);
9720             var tm = typeof monitorScroll;
9721             if(tm != 'undefined'){
9722                 Roo.EventManager.on(window, 'scroll', action, this,
9723                     {buffer: tm == 'number' ? monitorScroll : 50});
9724             }
9725             action.call(this); // align immediately
9726             return this;
9727         },
9728         /**
9729          * Clears any opacity settings from this element. Required in some cases for IE.
9730          * @return {Roo.Element} this
9731          */
9732         clearOpacity : function(){
9733             if (window.ActiveXObject) {
9734                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
9735                     this.dom.style.filter = "";
9736                 }
9737             } else {
9738                 this.dom.style.opacity = "";
9739                 this.dom.style["-moz-opacity"] = "";
9740                 this.dom.style["-khtml-opacity"] = "";
9741             }
9742             return this;
9743         },
9744
9745         /**
9746          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
9747          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9748          * @return {Roo.Element} this
9749          */
9750         hide : function(animate){
9751             this.setVisible(false, this.preanim(arguments, 0));
9752             return this;
9753         },
9754
9755         /**
9756         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
9757         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9758          * @return {Roo.Element} this
9759          */
9760         show : function(animate){
9761             this.setVisible(true, this.preanim(arguments, 0));
9762             return this;
9763         },
9764
9765         /**
9766          * @private Test if size has a unit, otherwise appends the default
9767          */
9768         addUnits : function(size){
9769             return Roo.Element.addUnits(size, this.defaultUnit);
9770         },
9771
9772         /**
9773          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
9774          * @return {Roo.Element} this
9775          */
9776         beginMeasure : function(){
9777             var el = this.dom;
9778             if(el.offsetWidth || el.offsetHeight){
9779                 return this; // offsets work already
9780             }
9781             var changed = [];
9782             var p = this.dom, b = document.body; // start with this element
9783             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
9784                 var pe = Roo.get(p);
9785                 if(pe.getStyle('display') == 'none'){
9786                     changed.push({el: p, visibility: pe.getStyle("visibility")});
9787                     p.style.visibility = "hidden";
9788                     p.style.display = "block";
9789                 }
9790                 p = p.parentNode;
9791             }
9792             this._measureChanged = changed;
9793             return this;
9794
9795         },
9796
9797         /**
9798          * Restores displays to before beginMeasure was called
9799          * @return {Roo.Element} this
9800          */
9801         endMeasure : function(){
9802             var changed = this._measureChanged;
9803             if(changed){
9804                 for(var i = 0, len = changed.length; i < len; i++) {
9805                     var r = changed[i];
9806                     r.el.style.visibility = r.visibility;
9807                     r.el.style.display = "none";
9808                 }
9809                 this._measureChanged = null;
9810             }
9811             return this;
9812         },
9813
9814         /**
9815         * Update the innerHTML of this element, optionally searching for and processing scripts
9816         * @param {String} html The new HTML
9817         * @param {Boolean} loadScripts (optional) true to look for and process scripts
9818         * @param {Function} callback For async script loading you can be noticed when the update completes
9819         * @return {Roo.Element} this
9820          */
9821         update : function(html, loadScripts, callback){
9822             if(typeof html == "undefined"){
9823                 html = "";
9824             }
9825             if(loadScripts !== true){
9826                 this.dom.innerHTML = html;
9827                 if(typeof callback == "function"){
9828                     callback();
9829                 }
9830                 return this;
9831             }
9832             var id = Roo.id();
9833             var dom = this.dom;
9834
9835             html += '<span id="' + id + '"></span>';
9836
9837             E.onAvailable(id, function(){
9838                 var hd = document.getElementsByTagName("head")[0];
9839                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
9840                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
9841                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
9842
9843                 var match;
9844                 while(match = re.exec(html)){
9845                     var attrs = match[1];
9846                     var srcMatch = attrs ? attrs.match(srcRe) : false;
9847                     if(srcMatch && srcMatch[2]){
9848                        var s = document.createElement("script");
9849                        s.src = srcMatch[2];
9850                        var typeMatch = attrs.match(typeRe);
9851                        if(typeMatch && typeMatch[2]){
9852                            s.type = typeMatch[2];
9853                        }
9854                        hd.appendChild(s);
9855                     }else if(match[2] && match[2].length > 0){
9856                         if(window.execScript) {
9857                            window.execScript(match[2]);
9858                         } else {
9859                             /**
9860                              * eval:var:id
9861                              * eval:var:dom
9862                              * eval:var:html
9863                              * 
9864                              */
9865                            window.eval(match[2]);
9866                         }
9867                     }
9868                 }
9869                 var el = document.getElementById(id);
9870                 if(el){el.parentNode.removeChild(el);}
9871                 if(typeof callback == "function"){
9872                     callback();
9873                 }
9874             });
9875             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
9876             return this;
9877         },
9878
9879         /**
9880          * Direct access to the UpdateManager update() method (takes the same parameters).
9881          * @param {String/Function} url The url for this request or a function to call to get the url
9882          * @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}
9883          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
9884          * @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.
9885          * @return {Roo.Element} this
9886          */
9887         load : function(){
9888             var um = this.getUpdateManager();
9889             um.update.apply(um, arguments);
9890             return this;
9891         },
9892
9893         /**
9894         * Gets this element's UpdateManager
9895         * @return {Roo.UpdateManager} The UpdateManager
9896         */
9897         getUpdateManager : function(){
9898             if(!this.updateManager){
9899                 this.updateManager = new Roo.UpdateManager(this);
9900             }
9901             return this.updateManager;
9902         },
9903
9904         /**
9905          * Disables text selection for this element (normalized across browsers)
9906          * @return {Roo.Element} this
9907          */
9908         unselectable : function(){
9909             this.dom.unselectable = "on";
9910             this.swallowEvent("selectstart", true);
9911             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
9912             this.addClass("x-unselectable");
9913             return this;
9914         },
9915
9916         /**
9917         * Calculates the x, y to center this element on the screen
9918         * @return {Array} The x, y values [x, y]
9919         */
9920         getCenterXY : function(){
9921             return this.getAlignToXY(document, 'c-c');
9922         },
9923
9924         /**
9925         * Centers the Element in either the viewport, or another Element.
9926         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
9927         */
9928         center : function(centerIn){
9929             this.alignTo(centerIn || document, 'c-c');
9930             return this;
9931         },
9932
9933         /**
9934          * Tests various css rules/browsers to determine if this element uses a border box
9935          * @return {Boolean}
9936          */
9937         isBorderBox : function(){
9938             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
9939         },
9940
9941         /**
9942          * Return a box {x, y, width, height} that can be used to set another elements
9943          * size/location to match this element.
9944          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
9945          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
9946          * @return {Object} box An object in the format {x, y, width, height}
9947          */
9948         getBox : function(contentBox, local){
9949             var xy;
9950             if(!local){
9951                 xy = this.getXY();
9952             }else{
9953                 var left = parseInt(this.getStyle("left"), 10) || 0;
9954                 var top = parseInt(this.getStyle("top"), 10) || 0;
9955                 xy = [left, top];
9956             }
9957             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
9958             if(!contentBox){
9959                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
9960             }else{
9961                 var l = this.getBorderWidth("l")+this.getPadding("l");
9962                 var r = this.getBorderWidth("r")+this.getPadding("r");
9963                 var t = this.getBorderWidth("t")+this.getPadding("t");
9964                 var b = this.getBorderWidth("b")+this.getPadding("b");
9965                 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)};
9966             }
9967             bx.right = bx.x + bx.width;
9968             bx.bottom = bx.y + bx.height;
9969             return bx;
9970         },
9971
9972         /**
9973          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
9974          for more information about the sides.
9975          * @param {String} sides
9976          * @return {Number}
9977          */
9978         getFrameWidth : function(sides, onlyContentBox){
9979             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
9980         },
9981
9982         /**
9983          * 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.
9984          * @param {Object} box The box to fill {x, y, width, height}
9985          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
9986          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9987          * @return {Roo.Element} this
9988          */
9989         setBox : function(box, adjust, animate){
9990             var w = box.width, h = box.height;
9991             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
9992                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
9993                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
9994             }
9995             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
9996             return this;
9997         },
9998
9999         /**
10000          * Forces the browser to repaint this element
10001          * @return {Roo.Element} this
10002          */
10003          repaint : function(){
10004             var dom = this.dom;
10005             this.addClass("x-repaint");
10006             setTimeout(function(){
10007                 Roo.get(dom).removeClass("x-repaint");
10008             }, 1);
10009             return this;
10010         },
10011
10012         /**
10013          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
10014          * then it returns the calculated width of the sides (see getPadding)
10015          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
10016          * @return {Object/Number}
10017          */
10018         getMargins : function(side){
10019             if(!side){
10020                 return {
10021                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
10022                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
10023                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
10024                     right: parseInt(this.getStyle("margin-right"), 10) || 0
10025                 };
10026             }else{
10027                 return this.addStyles(side, El.margins);
10028              }
10029         },
10030
10031         // private
10032         addStyles : function(sides, styles){
10033             var val = 0, v, w;
10034             for(var i = 0, len = sides.length; i < len; i++){
10035                 v = this.getStyle(styles[sides.charAt(i)]);
10036                 if(v){
10037                      w = parseInt(v, 10);
10038                      if(w){ val += w; }
10039                 }
10040             }
10041             return val;
10042         },
10043
10044         /**
10045          * Creates a proxy element of this element
10046          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
10047          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
10048          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
10049          * @return {Roo.Element} The new proxy element
10050          */
10051         createProxy : function(config, renderTo, matchBox){
10052             if(renderTo){
10053                 renderTo = Roo.getDom(renderTo);
10054             }else{
10055                 renderTo = document.body;
10056             }
10057             config = typeof config == "object" ?
10058                 config : {tag : "div", cls: config};
10059             var proxy = Roo.DomHelper.append(renderTo, config, true);
10060             if(matchBox){
10061                proxy.setBox(this.getBox());
10062             }
10063             return proxy;
10064         },
10065
10066         /**
10067          * Puts a mask over this element to disable user interaction. Requires core.css.
10068          * This method can only be applied to elements which accept child nodes.
10069          * @param {String} msg (optional) A message to display in the mask
10070          * @param {String} msgCls (optional) A css class to apply to the msg element - use no-spinner to hide the spinner on bootstrap
10071          * @return {Element} The mask  element
10072          */
10073         mask : function(msg, msgCls)
10074         {
10075             if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
10076                 this.setStyle("position", "relative");
10077             }
10078             if(!this._mask){
10079                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
10080             }
10081             
10082             this.addClass("x-masked");
10083             this._mask.setDisplayed(true);
10084             
10085             // we wander
10086             var z = 0;
10087             var dom = this.dom;
10088             while (dom && dom.style) {
10089                 if (!isNaN(parseInt(dom.style.zIndex))) {
10090                     z = Math.max(z, parseInt(dom.style.zIndex));
10091                 }
10092                 dom = dom.parentNode;
10093             }
10094             // if we are masking the body - then it hides everything..
10095             if (this.dom == document.body) {
10096                 z = 1000000;
10097                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
10098                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
10099             }
10100            
10101             if(typeof msg == 'string'){
10102                 if(!this._maskMsg){
10103                     this._maskMsg = Roo.DomHelper.append(this.dom, {
10104                         cls: "roo-el-mask-msg", 
10105                         cn: [
10106                             {
10107                                 tag: 'i',
10108                                 cls: 'fa fa-spinner fa-spin'
10109                             },
10110                             {
10111                                 tag: 'div'
10112                             }   
10113                         ]
10114                     }, true);
10115                 }
10116                 var mm = this._maskMsg;
10117                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
10118                 if (mm.dom.lastChild) { // weird IE issue?
10119                     mm.dom.lastChild.innerHTML = msg;
10120                 }
10121                 mm.setDisplayed(true);
10122                 mm.center(this);
10123                 mm.setStyle('z-index', z + 102);
10124             }
10125             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
10126                 this._mask.setHeight(this.getHeight());
10127             }
10128             this._mask.setStyle('z-index', z + 100);
10129             
10130             return this._mask;
10131         },
10132
10133         /**
10134          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
10135          * it is cached for reuse.
10136          */
10137         unmask : function(removeEl){
10138             if(this._mask){
10139                 if(removeEl === true){
10140                     this._mask.remove();
10141                     delete this._mask;
10142                     if(this._maskMsg){
10143                         this._maskMsg.remove();
10144                         delete this._maskMsg;
10145                     }
10146                 }else{
10147                     this._mask.setDisplayed(false);
10148                     if(this._maskMsg){
10149                         this._maskMsg.setDisplayed(false);
10150                     }
10151                 }
10152             }
10153             this.removeClass("x-masked");
10154         },
10155
10156         /**
10157          * Returns true if this element is masked
10158          * @return {Boolean}
10159          */
10160         isMasked : function(){
10161             return this._mask && this._mask.isVisible();
10162         },
10163
10164         /**
10165          * Creates an iframe shim for this element to keep selects and other windowed objects from
10166          * showing through.
10167          * @return {Roo.Element} The new shim element
10168          */
10169         createShim : function(){
10170             var el = document.createElement('iframe');
10171             el.frameBorder = 'no';
10172             el.className = 'roo-shim';
10173             if(Roo.isIE && Roo.isSecure){
10174                 el.src = Roo.SSL_SECURE_URL;
10175             }
10176             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
10177             shim.autoBoxAdjust = false;
10178             return shim;
10179         },
10180
10181         /**
10182          * Removes this element from the DOM and deletes it from the cache
10183          */
10184         remove : function(){
10185             if(this.dom.parentNode){
10186                 this.dom.parentNode.removeChild(this.dom);
10187             }
10188             delete El.cache[this.dom.id];
10189         },
10190
10191         /**
10192          * Sets up event handlers to add and remove a css class when the mouse is over this element
10193          * @param {String} className
10194          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
10195          * mouseout events for children elements
10196          * @return {Roo.Element} this
10197          */
10198         addClassOnOver : function(className, preventFlicker){
10199             this.on("mouseover", function(){
10200                 Roo.fly(this, '_internal').addClass(className);
10201             }, this.dom);
10202             var removeFn = function(e){
10203                 if(preventFlicker !== true || !e.within(this, true)){
10204                     Roo.fly(this, '_internal').removeClass(className);
10205                 }
10206             };
10207             this.on("mouseout", removeFn, this.dom);
10208             return this;
10209         },
10210
10211         /**
10212          * Sets up event handlers to add and remove a css class when this element has the focus
10213          * @param {String} className
10214          * @return {Roo.Element} this
10215          */
10216         addClassOnFocus : function(className){
10217             this.on("focus", function(){
10218                 Roo.fly(this, '_internal').addClass(className);
10219             }, this.dom);
10220             this.on("blur", function(){
10221                 Roo.fly(this, '_internal').removeClass(className);
10222             }, this.dom);
10223             return this;
10224         },
10225         /**
10226          * 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)
10227          * @param {String} className
10228          * @return {Roo.Element} this
10229          */
10230         addClassOnClick : function(className){
10231             var dom = this.dom;
10232             this.on("mousedown", function(){
10233                 Roo.fly(dom, '_internal').addClass(className);
10234                 var d = Roo.get(document);
10235                 var fn = function(){
10236                     Roo.fly(dom, '_internal').removeClass(className);
10237                     d.removeListener("mouseup", fn);
10238                 };
10239                 d.on("mouseup", fn);
10240             });
10241             return this;
10242         },
10243
10244         /**
10245          * Stops the specified event from bubbling and optionally prevents the default action
10246          * @param {String} eventName
10247          * @param {Boolean} preventDefault (optional) true to prevent the default action too
10248          * @return {Roo.Element} this
10249          */
10250         swallowEvent : function(eventName, preventDefault){
10251             var fn = function(e){
10252                 e.stopPropagation();
10253                 if(preventDefault){
10254                     e.preventDefault();
10255                 }
10256             };
10257             if(eventName instanceof Array){
10258                 for(var i = 0, len = eventName.length; i < len; i++){
10259                      this.on(eventName[i], fn);
10260                 }
10261                 return this;
10262             }
10263             this.on(eventName, fn);
10264             return this;
10265         },
10266
10267         /**
10268          * @private
10269          */
10270         fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
10271
10272         /**
10273          * Sizes this element to its parent element's dimensions performing
10274          * neccessary box adjustments.
10275          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
10276          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
10277          * @return {Roo.Element} this
10278          */
10279         fitToParent : function(monitorResize, targetParent) {
10280           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
10281           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
10282           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
10283             return this;
10284           }
10285           var p = Roo.get(targetParent || this.dom.parentNode);
10286           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
10287           if (monitorResize === true) {
10288             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
10289             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
10290           }
10291           return this;
10292         },
10293
10294         /**
10295          * Gets the next sibling, skipping text nodes
10296          * @return {HTMLElement} The next sibling or null
10297          */
10298         getNextSibling : function(){
10299             var n = this.dom.nextSibling;
10300             while(n && n.nodeType != 1){
10301                 n = n.nextSibling;
10302             }
10303             return n;
10304         },
10305
10306         /**
10307          * Gets the previous sibling, skipping text nodes
10308          * @return {HTMLElement} The previous sibling or null
10309          */
10310         getPrevSibling : function(){
10311             var n = this.dom.previousSibling;
10312             while(n && n.nodeType != 1){
10313                 n = n.previousSibling;
10314             }
10315             return n;
10316         },
10317
10318
10319         /**
10320          * Appends the passed element(s) to this element
10321          * @param {String/HTMLElement/Array/Element/CompositeElement} el
10322          * @return {Roo.Element} this
10323          */
10324         appendChild: function(el){
10325             el = Roo.get(el);
10326             el.appendTo(this);
10327             return this;
10328         },
10329
10330         /**
10331          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
10332          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
10333          * automatically generated with the specified attributes.
10334          * @param {HTMLElement} insertBefore (optional) a child element of this element
10335          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
10336          * @return {Roo.Element} The new child element
10337          */
10338         createChild: function(config, insertBefore, returnDom){
10339             config = config || {tag:'div'};
10340             if(insertBefore){
10341                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
10342             }
10343             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
10344         },
10345
10346         /**
10347          * Appends this element to the passed element
10348          * @param {String/HTMLElement/Element} el The new parent element
10349          * @return {Roo.Element} this
10350          */
10351         appendTo: function(el){
10352             el = Roo.getDom(el);
10353             el.appendChild(this.dom);
10354             return this;
10355         },
10356
10357         /**
10358          * Inserts this element before the passed element in the DOM
10359          * @param {String/HTMLElement/Element} el The element to insert before
10360          * @return {Roo.Element} this
10361          */
10362         insertBefore: function(el){
10363             el = Roo.getDom(el);
10364             el.parentNode.insertBefore(this.dom, el);
10365             return this;
10366         },
10367
10368         /**
10369          * Inserts this element after the passed element in the DOM
10370          * @param {String/HTMLElement/Element} el The element to insert after
10371          * @return {Roo.Element} this
10372          */
10373         insertAfter: function(el){
10374             el = Roo.getDom(el);
10375             el.parentNode.insertBefore(this.dom, el.nextSibling);
10376             return this;
10377         },
10378
10379         /**
10380          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
10381          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
10382          * @return {Roo.Element} The new child
10383          */
10384         insertFirst: function(el, returnDom){
10385             el = el || {};
10386             if(typeof el == 'object' && !el.nodeType){ // dh config
10387                 return this.createChild(el, this.dom.firstChild, returnDom);
10388             }else{
10389                 el = Roo.getDom(el);
10390                 this.dom.insertBefore(el, this.dom.firstChild);
10391                 return !returnDom ? Roo.get(el) : el;
10392             }
10393         },
10394
10395         /**
10396          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
10397          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
10398          * @param {String} where (optional) 'before' or 'after' defaults to before
10399          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
10400          * @return {Roo.Element} the inserted Element
10401          */
10402         insertSibling: function(el, where, returnDom){
10403             where = where ? where.toLowerCase() : 'before';
10404             el = el || {};
10405             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
10406
10407             if(typeof el == 'object' && !el.nodeType){ // dh config
10408                 if(where == 'after' && !this.dom.nextSibling){
10409                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
10410                 }else{
10411                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
10412                 }
10413
10414             }else{
10415                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
10416                             where == 'before' ? this.dom : this.dom.nextSibling);
10417                 if(!returnDom){
10418                     rt = Roo.get(rt);
10419                 }
10420             }
10421             return rt;
10422         },
10423
10424         /**
10425          * Creates and wraps this element with another element
10426          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
10427          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
10428          * @return {HTMLElement/Element} The newly created wrapper element
10429          */
10430         wrap: function(config, returnDom){
10431             if(!config){
10432                 config = {tag: "div"};
10433             }
10434             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
10435             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
10436             return newEl;
10437         },
10438
10439         /**
10440          * Replaces the passed element with this element
10441          * @param {String/HTMLElement/Element} el The element to replace
10442          * @return {Roo.Element} this
10443          */
10444         replace: function(el){
10445             el = Roo.get(el);
10446             this.insertBefore(el);
10447             el.remove();
10448             return this;
10449         },
10450
10451         /**
10452          * Inserts an html fragment into this element
10453          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
10454          * @param {String} html The HTML fragment
10455          * @param {Boolean} returnEl True to return an Roo.Element
10456          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
10457          */
10458         insertHtml : function(where, html, returnEl){
10459             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
10460             return returnEl ? Roo.get(el) : el;
10461         },
10462
10463         /**
10464          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
10465          * @param {Object} o The object with the attributes
10466          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
10467          * @return {Roo.Element} this
10468          */
10469         set : function(o, useSet){
10470             var el = this.dom;
10471             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
10472             for(var attr in o){
10473                 if(attr == "style" || typeof o[attr] == "function")  { continue; }
10474                 if(attr=="cls"){
10475                     el.className = o["cls"];
10476                 }else{
10477                     if(useSet) {
10478                         el.setAttribute(attr, o[attr]);
10479                     } else {
10480                         el[attr] = o[attr];
10481                     }
10482                 }
10483             }
10484             if(o.style){
10485                 Roo.DomHelper.applyStyles(el, o.style);
10486             }
10487             return this;
10488         },
10489
10490         /**
10491          * Convenience method for constructing a KeyMap
10492          * @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:
10493          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
10494          * @param {Function} fn The function to call
10495          * @param {Object} scope (optional) The scope of the function
10496          * @return {Roo.KeyMap} The KeyMap created
10497          */
10498         addKeyListener : function(key, fn, scope){
10499             var config;
10500             if(typeof key != "object" || key instanceof Array){
10501                 config = {
10502                     key: key,
10503                     fn: fn,
10504                     scope: scope
10505                 };
10506             }else{
10507                 config = {
10508                     key : key.key,
10509                     shift : key.shift,
10510                     ctrl : key.ctrl,
10511                     alt : key.alt,
10512                     fn: fn,
10513                     scope: scope
10514                 };
10515             }
10516             return new Roo.KeyMap(this, config);
10517         },
10518
10519         /**
10520          * Creates a KeyMap for this element
10521          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
10522          * @return {Roo.KeyMap} The KeyMap created
10523          */
10524         addKeyMap : function(config){
10525             return new Roo.KeyMap(this, config);
10526         },
10527
10528         /**
10529          * Returns true if this element is scrollable.
10530          * @return {Boolean}
10531          */
10532          isScrollable : function(){
10533             var dom = this.dom;
10534             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
10535         },
10536
10537         /**
10538          * 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().
10539          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
10540          * @param {Number} value The new scroll value
10541          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10542          * @return {Element} this
10543          */
10544
10545         scrollTo : function(side, value, animate){
10546             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
10547             if(!animate || !A){
10548                 this.dom[prop] = value;
10549             }else{
10550                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
10551                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
10552             }
10553             return this;
10554         },
10555
10556         /**
10557          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
10558          * within this element's scrollable range.
10559          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
10560          * @param {Number} distance How far to scroll the element in pixels
10561          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10562          * @return {Boolean} Returns true if a scroll was triggered or false if the element
10563          * was scrolled as far as it could go.
10564          */
10565          scroll : function(direction, distance, animate){
10566              if(!this.isScrollable()){
10567                  return;
10568              }
10569              var el = this.dom;
10570              var l = el.scrollLeft, t = el.scrollTop;
10571              var w = el.scrollWidth, h = el.scrollHeight;
10572              var cw = el.clientWidth, ch = el.clientHeight;
10573              direction = direction.toLowerCase();
10574              var scrolled = false;
10575              var a = this.preanim(arguments, 2);
10576              switch(direction){
10577                  case "l":
10578                  case "left":
10579                      if(w - l > cw){
10580                          var v = Math.min(l + distance, w-cw);
10581                          this.scrollTo("left", v, a);
10582                          scrolled = true;
10583                      }
10584                      break;
10585                 case "r":
10586                 case "right":
10587                      if(l > 0){
10588                          var v = Math.max(l - distance, 0);
10589                          this.scrollTo("left", v, a);
10590                          scrolled = true;
10591                      }
10592                      break;
10593                 case "t":
10594                 case "top":
10595                 case "up":
10596                      if(t > 0){
10597                          var v = Math.max(t - distance, 0);
10598                          this.scrollTo("top", v, a);
10599                          scrolled = true;
10600                      }
10601                      break;
10602                 case "b":
10603                 case "bottom":
10604                 case "down":
10605                      if(h - t > ch){
10606                          var v = Math.min(t + distance, h-ch);
10607                          this.scrollTo("top", v, a);
10608                          scrolled = true;
10609                      }
10610                      break;
10611              }
10612              return scrolled;
10613         },
10614
10615         /**
10616          * Translates the passed page coordinates into left/top css values for this element
10617          * @param {Number/Array} x The page x or an array containing [x, y]
10618          * @param {Number} y The page y
10619          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
10620          */
10621         translatePoints : function(x, y){
10622             if(typeof x == 'object' || x instanceof Array){
10623                 y = x[1]; x = x[0];
10624             }
10625             var p = this.getStyle('position');
10626             var o = this.getXY();
10627
10628             var l = parseInt(this.getStyle('left'), 10);
10629             var t = parseInt(this.getStyle('top'), 10);
10630
10631             if(isNaN(l)){
10632                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
10633             }
10634             if(isNaN(t)){
10635                 t = (p == "relative") ? 0 : this.dom.offsetTop;
10636             }
10637
10638             return {left: (x - o[0] + l), top: (y - o[1] + t)};
10639         },
10640
10641         /**
10642          * Returns the current scroll position of the element.
10643          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
10644          */
10645         getScroll : function(){
10646             var d = this.dom, doc = document;
10647             if(d == doc || d == doc.body){
10648                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
10649                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
10650                 return {left: l, top: t};
10651             }else{
10652                 return {left: d.scrollLeft, top: d.scrollTop};
10653             }
10654         },
10655
10656         /**
10657          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
10658          * are convert to standard 6 digit hex color.
10659          * @param {String} attr The css attribute
10660          * @param {String} defaultValue The default value to use when a valid color isn't found
10661          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
10662          * YUI color anims.
10663          */
10664         getColor : function(attr, defaultValue, prefix){
10665             var v = this.getStyle(attr);
10666             if(!v || v == "transparent" || v == "inherit") {
10667                 return defaultValue;
10668             }
10669             var color = typeof prefix == "undefined" ? "#" : prefix;
10670             if(v.substr(0, 4) == "rgb("){
10671                 var rvs = v.slice(4, v.length -1).split(",");
10672                 for(var i = 0; i < 3; i++){
10673                     var h = parseInt(rvs[i]).toString(16);
10674                     if(h < 16){
10675                         h = "0" + h;
10676                     }
10677                     color += h;
10678                 }
10679             } else {
10680                 if(v.substr(0, 1) == "#"){
10681                     if(v.length == 4) {
10682                         for(var i = 1; i < 4; i++){
10683                             var c = v.charAt(i);
10684                             color +=  c + c;
10685                         }
10686                     }else if(v.length == 7){
10687                         color += v.substr(1);
10688                     }
10689                 }
10690             }
10691             return(color.length > 5 ? color.toLowerCase() : defaultValue);
10692         },
10693
10694         /**
10695          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
10696          * gradient background, rounded corners and a 4-way shadow.
10697          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
10698          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
10699          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
10700          * @return {Roo.Element} this
10701          */
10702         boxWrap : function(cls){
10703             cls = cls || 'x-box';
10704             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
10705             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
10706             return el;
10707         },
10708
10709         /**
10710          * Returns the value of a namespaced attribute from the element's underlying DOM node.
10711          * @param {String} namespace The namespace in which to look for the attribute
10712          * @param {String} name The attribute name
10713          * @return {String} The attribute value
10714          */
10715         getAttributeNS : Roo.isIE ? function(ns, name){
10716             var d = this.dom;
10717             var type = typeof d[ns+":"+name];
10718             if(type != 'undefined' && type != 'unknown'){
10719                 return d[ns+":"+name];
10720             }
10721             return d[name];
10722         } : function(ns, name){
10723             var d = this.dom;
10724             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
10725         },
10726         
10727         
10728         /**
10729          * Sets or Returns the value the dom attribute value
10730          * @param {String|Object} name The attribute name (or object to set multiple attributes)
10731          * @param {String} value (optional) The value to set the attribute to
10732          * @return {String} The attribute value
10733          */
10734         attr : function(name){
10735             if (arguments.length > 1) {
10736                 this.dom.setAttribute(name, arguments[1]);
10737                 return arguments[1];
10738             }
10739             if (typeof(name) == 'object') {
10740                 for(var i in name) {
10741                     this.attr(i, name[i]);
10742                 }
10743                 return name;
10744             }
10745             
10746             
10747             if (!this.dom.hasAttribute(name)) {
10748                 return undefined;
10749             }
10750             return this.dom.getAttribute(name);
10751         }
10752         
10753         
10754         
10755     };
10756
10757     var ep = El.prototype;
10758
10759     /**
10760      * Appends an event handler (Shorthand for addListener)
10761      * @param {String}   eventName     The type of event to append
10762      * @param {Function} fn        The method the event invokes
10763      * @param {Object} scope       (optional) The scope (this object) of the fn
10764      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
10765      * @method
10766      */
10767     ep.on = ep.addListener;
10768         // backwards compat
10769     ep.mon = ep.addListener;
10770
10771     /**
10772      * Removes an event handler from this element (shorthand for removeListener)
10773      * @param {String} eventName the type of event to remove
10774      * @param {Function} fn the method the event invokes
10775      * @return {Roo.Element} this
10776      * @method
10777      */
10778     ep.un = ep.removeListener;
10779
10780     /**
10781      * true to automatically adjust width and height settings for box-model issues (default to true)
10782      */
10783     ep.autoBoxAdjust = true;
10784
10785     // private
10786     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
10787
10788     // private
10789     El.addUnits = function(v, defaultUnit){
10790         if(v === "" || v == "auto"){
10791             return v;
10792         }
10793         if(v === undefined){
10794             return '';
10795         }
10796         if(typeof v == "number" || !El.unitPattern.test(v)){
10797             return v + (defaultUnit || 'px');
10798         }
10799         return v;
10800     };
10801
10802     // special markup used throughout Roo when box wrapping elements
10803     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>';
10804     /**
10805      * Visibility mode constant - Use visibility to hide element
10806      * @static
10807      * @type Number
10808      */
10809     El.VISIBILITY = 1;
10810     /**
10811      * Visibility mode constant - Use display to hide element
10812      * @static
10813      * @type Number
10814      */
10815     El.DISPLAY = 2;
10816
10817     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
10818     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
10819     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
10820
10821
10822
10823     /**
10824      * @private
10825      */
10826     El.cache = {};
10827
10828     var docEl;
10829
10830     /**
10831      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
10832      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
10833      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
10834      * @return {Element} The Element object
10835      * @static
10836      */
10837     El.get = function(el){
10838         var ex, elm, id;
10839         if(!el){ return null; }
10840         if(typeof el == "string"){ // element id
10841             if(!(elm = document.getElementById(el))){
10842                 return null;
10843             }
10844             if(ex = El.cache[el]){
10845                 ex.dom = elm;
10846             }else{
10847                 ex = El.cache[el] = new El(elm);
10848             }
10849             return ex;
10850         }else if(el.tagName){ // dom element
10851             if(!(id = el.id)){
10852                 id = Roo.id(el);
10853             }
10854             if(ex = El.cache[id]){
10855                 ex.dom = el;
10856             }else{
10857                 ex = El.cache[id] = new El(el);
10858             }
10859             return ex;
10860         }else if(el instanceof El){
10861             if(el != docEl){
10862                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
10863                                                               // catch case where it hasn't been appended
10864                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
10865             }
10866             return el;
10867         }else if(el.isComposite){
10868             return el;
10869         }else if(el instanceof Array){
10870             return El.select(el);
10871         }else if(el == document){
10872             // create a bogus element object representing the document object
10873             if(!docEl){
10874                 var f = function(){};
10875                 f.prototype = El.prototype;
10876                 docEl = new f();
10877                 docEl.dom = document;
10878             }
10879             return docEl;
10880         }
10881         return null;
10882     };
10883
10884     // private
10885     El.uncache = function(el){
10886         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
10887             if(a[i]){
10888                 delete El.cache[a[i].id || a[i]];
10889             }
10890         }
10891     };
10892
10893     // private
10894     // Garbage collection - uncache elements/purge listeners on orphaned elements
10895     // so we don't hold a reference and cause the browser to retain them
10896     El.garbageCollect = function(){
10897         if(!Roo.enableGarbageCollector){
10898             clearInterval(El.collectorThread);
10899             return;
10900         }
10901         for(var eid in El.cache){
10902             var el = El.cache[eid], d = el.dom;
10903             // -------------------------------------------------------
10904             // Determining what is garbage:
10905             // -------------------------------------------------------
10906             // !d
10907             // dom node is null, definitely garbage
10908             // -------------------------------------------------------
10909             // !d.parentNode
10910             // no parentNode == direct orphan, definitely garbage
10911             // -------------------------------------------------------
10912             // !d.offsetParent && !document.getElementById(eid)
10913             // display none elements have no offsetParent so we will
10914             // also try to look it up by it's id. However, check
10915             // offsetParent first so we don't do unneeded lookups.
10916             // This enables collection of elements that are not orphans
10917             // directly, but somewhere up the line they have an orphan
10918             // parent.
10919             // -------------------------------------------------------
10920             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
10921                 delete El.cache[eid];
10922                 if(d && Roo.enableListenerCollection){
10923                     E.purgeElement(d);
10924                 }
10925             }
10926         }
10927     }
10928     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
10929
10930
10931     // dom is optional
10932     El.Flyweight = function(dom){
10933         this.dom = dom;
10934     };
10935     El.Flyweight.prototype = El.prototype;
10936
10937     El._flyweights = {};
10938     /**
10939      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
10940      * the dom node can be overwritten by other code.
10941      * @param {String/HTMLElement} el The dom node or id
10942      * @param {String} named (optional) Allows for creation of named reusable flyweights to
10943      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
10944      * @static
10945      * @return {Element} The shared Element object
10946      */
10947     El.fly = function(el, named){
10948         named = named || '_global';
10949         el = Roo.getDom(el);
10950         if(!el){
10951             return null;
10952         }
10953         if(!El._flyweights[named]){
10954             El._flyweights[named] = new El.Flyweight();
10955         }
10956         El._flyweights[named].dom = el;
10957         return El._flyweights[named];
10958     };
10959
10960     /**
10961      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
10962      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
10963      * Shorthand of {@link Roo.Element#get}
10964      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
10965      * @return {Element} The Element object
10966      * @member Roo
10967      * @method get
10968      */
10969     Roo.get = El.get;
10970     /**
10971      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
10972      * the dom node can be overwritten by other code.
10973      * Shorthand of {@link Roo.Element#fly}
10974      * @param {String/HTMLElement} el The dom node or id
10975      * @param {String} named (optional) Allows for creation of named reusable flyweights to
10976      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
10977      * @static
10978      * @return {Element} The shared Element object
10979      * @member Roo
10980      * @method fly
10981      */
10982     Roo.fly = El.fly;
10983
10984     // speedy lookup for elements never to box adjust
10985     var noBoxAdjust = Roo.isStrict ? {
10986         select:1
10987     } : {
10988         input:1, select:1, textarea:1
10989     };
10990     if(Roo.isIE || Roo.isGecko){
10991         noBoxAdjust['button'] = 1;
10992     }
10993
10994
10995     Roo.EventManager.on(window, 'unload', function(){
10996         delete El.cache;
10997         delete El._flyweights;
10998     });
10999 })();
11000
11001
11002
11003
11004 if(Roo.DomQuery){
11005     Roo.Element.selectorFunction = Roo.DomQuery.select;
11006 }
11007
11008 Roo.Element.select = function(selector, unique, root){
11009     var els;
11010     if(typeof selector == "string"){
11011         els = Roo.Element.selectorFunction(selector, root);
11012     }else if(selector.length !== undefined){
11013         els = selector;
11014     }else{
11015         throw "Invalid selector";
11016     }
11017     if(unique === true){
11018         return new Roo.CompositeElement(els);
11019     }else{
11020         return new Roo.CompositeElementLite(els);
11021     }
11022 };
11023 /**
11024  * Selects elements based on the passed CSS selector to enable working on them as 1.
11025  * @param {String/Array} selector The CSS selector or an array of elements
11026  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
11027  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
11028  * @return {CompositeElementLite/CompositeElement}
11029  * @member Roo
11030  * @method select
11031  */
11032 Roo.select = Roo.Element.select;
11033
11034
11035
11036
11037
11038
11039
11040
11041
11042
11043
11044
11045
11046
11047 /*
11048  * Based on:
11049  * Ext JS Library 1.1.1
11050  * Copyright(c) 2006-2007, Ext JS, LLC.
11051  *
11052  * Originally Released Under LGPL - original licence link has changed is not relivant.
11053  *
11054  * Fork - LGPL
11055  * <script type="text/javascript">
11056  */
11057
11058
11059
11060 //Notifies Element that fx methods are available
11061 Roo.enableFx = true;
11062
11063 /**
11064  * @class Roo.Fx
11065  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
11066  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
11067  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
11068  * Element effects to work.</p><br/>
11069  *
11070  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
11071  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
11072  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
11073  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
11074  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
11075  * expected results and should be done with care.</p><br/>
11076  *
11077  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
11078  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
11079 <pre>
11080 Value  Description
11081 -----  -----------------------------
11082 tl     The top left corner
11083 t      The center of the top edge
11084 tr     The top right corner
11085 l      The center of the left edge
11086 r      The center of the right edge
11087 bl     The bottom left corner
11088 b      The center of the bottom edge
11089 br     The bottom right corner
11090 </pre>
11091  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
11092  * below are common options that can be passed to any Fx method.</b>
11093  * @cfg {Function} callback A function called when the effect is finished
11094  * @cfg {Object} scope The scope of the effect function
11095  * @cfg {String} easing A valid Easing value for the effect
11096  * @cfg {String} afterCls A css class to apply after the effect
11097  * @cfg {Number} duration The length of time (in seconds) that the effect should last
11098  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
11099  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
11100  * effects that end with the element being visually hidden, ignored otherwise)
11101  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
11102  * a function which returns such a specification that will be applied to the Element after the effect finishes
11103  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
11104  * @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
11105  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
11106  */
11107 Roo.Fx = {
11108         /**
11109          * Slides the element into view.  An anchor point can be optionally passed to set the point of
11110          * origin for the slide effect.  This function automatically handles wrapping the element with
11111          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
11112          * Usage:
11113          *<pre><code>
11114 // default: slide the element in from the top
11115 el.slideIn();
11116
11117 // custom: slide the element in from the right with a 2-second duration
11118 el.slideIn('r', { duration: 2 });
11119
11120 // common config options shown with default values
11121 el.slideIn('t', {
11122     easing: 'easeOut',
11123     duration: .5
11124 });
11125 </code></pre>
11126          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
11127          * @param {Object} options (optional) Object literal with any of the Fx config options
11128          * @return {Roo.Element} The Element
11129          */
11130     slideIn : function(anchor, o){
11131         var el = this.getFxEl();
11132         o = o || {};
11133
11134         el.queueFx(o, function(){
11135
11136             anchor = anchor || "t";
11137
11138             // fix display to visibility
11139             this.fixDisplay();
11140
11141             // restore values after effect
11142             var r = this.getFxRestore();
11143             var b = this.getBox();
11144             // fixed size for slide
11145             this.setSize(b);
11146
11147             // wrap if needed
11148             var wrap = this.fxWrap(r.pos, o, "hidden");
11149
11150             var st = this.dom.style;
11151             st.visibility = "visible";
11152             st.position = "absolute";
11153
11154             // clear out temp styles after slide and unwrap
11155             var after = function(){
11156                 el.fxUnwrap(wrap, r.pos, o);
11157                 st.width = r.width;
11158                 st.height = r.height;
11159                 el.afterFx(o);
11160             };
11161             // time to calc the positions
11162             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
11163
11164             switch(anchor.toLowerCase()){
11165                 case "t":
11166                     wrap.setSize(b.width, 0);
11167                     st.left = st.bottom = "0";
11168                     a = {height: bh};
11169                 break;
11170                 case "l":
11171                     wrap.setSize(0, b.height);
11172                     st.right = st.top = "0";
11173                     a = {width: bw};
11174                 break;
11175                 case "r":
11176                     wrap.setSize(0, b.height);
11177                     wrap.setX(b.right);
11178                     st.left = st.top = "0";
11179                     a = {width: bw, points: pt};
11180                 break;
11181                 case "b":
11182                     wrap.setSize(b.width, 0);
11183                     wrap.setY(b.bottom);
11184                     st.left = st.top = "0";
11185                     a = {height: bh, points: pt};
11186                 break;
11187                 case "tl":
11188                     wrap.setSize(0, 0);
11189                     st.right = st.bottom = "0";
11190                     a = {width: bw, height: bh};
11191                 break;
11192                 case "bl":
11193                     wrap.setSize(0, 0);
11194                     wrap.setY(b.y+b.height);
11195                     st.right = st.top = "0";
11196                     a = {width: bw, height: bh, points: pt};
11197                 break;
11198                 case "br":
11199                     wrap.setSize(0, 0);
11200                     wrap.setXY([b.right, b.bottom]);
11201                     st.left = st.top = "0";
11202                     a = {width: bw, height: bh, points: pt};
11203                 break;
11204                 case "tr":
11205                     wrap.setSize(0, 0);
11206                     wrap.setX(b.x+b.width);
11207                     st.left = st.bottom = "0";
11208                     a = {width: bw, height: bh, points: pt};
11209                 break;
11210             }
11211             this.dom.style.visibility = "visible";
11212             wrap.show();
11213
11214             arguments.callee.anim = wrap.fxanim(a,
11215                 o,
11216                 'motion',
11217                 .5,
11218                 'easeOut', after);
11219         });
11220         return this;
11221     },
11222     
11223         /**
11224          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
11225          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
11226          * 'hidden') but block elements will still take up space in the document.  The element must be removed
11227          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
11228          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
11229          * Usage:
11230          *<pre><code>
11231 // default: slide the element out to the top
11232 el.slideOut();
11233
11234 // custom: slide the element out to the right with a 2-second duration
11235 el.slideOut('r', { duration: 2 });
11236
11237 // common config options shown with default values
11238 el.slideOut('t', {
11239     easing: 'easeOut',
11240     duration: .5,
11241     remove: false,
11242     useDisplay: false
11243 });
11244 </code></pre>
11245          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
11246          * @param {Object} options (optional) Object literal with any of the Fx config options
11247          * @return {Roo.Element} The Element
11248          */
11249     slideOut : function(anchor, o){
11250         var el = this.getFxEl();
11251         o = o || {};
11252
11253         el.queueFx(o, function(){
11254
11255             anchor = anchor || "t";
11256
11257             // restore values after effect
11258             var r = this.getFxRestore();
11259             
11260             var b = this.getBox();
11261             // fixed size for slide
11262             this.setSize(b);
11263
11264             // wrap if needed
11265             var wrap = this.fxWrap(r.pos, o, "visible");
11266
11267             var st = this.dom.style;
11268             st.visibility = "visible";
11269             st.position = "absolute";
11270
11271             wrap.setSize(b);
11272
11273             var after = function(){
11274                 if(o.useDisplay){
11275                     el.setDisplayed(false);
11276                 }else{
11277                     el.hide();
11278                 }
11279
11280                 el.fxUnwrap(wrap, r.pos, o);
11281
11282                 st.width = r.width;
11283                 st.height = r.height;
11284
11285                 el.afterFx(o);
11286             };
11287
11288             var a, zero = {to: 0};
11289             switch(anchor.toLowerCase()){
11290                 case "t":
11291                     st.left = st.bottom = "0";
11292                     a = {height: zero};
11293                 break;
11294                 case "l":
11295                     st.right = st.top = "0";
11296                     a = {width: zero};
11297                 break;
11298                 case "r":
11299                     st.left = st.top = "0";
11300                     a = {width: zero, points: {to:[b.right, b.y]}};
11301                 break;
11302                 case "b":
11303                     st.left = st.top = "0";
11304                     a = {height: zero, points: {to:[b.x, b.bottom]}};
11305                 break;
11306                 case "tl":
11307                     st.right = st.bottom = "0";
11308                     a = {width: zero, height: zero};
11309                 break;
11310                 case "bl":
11311                     st.right = st.top = "0";
11312                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
11313                 break;
11314                 case "br":
11315                     st.left = st.top = "0";
11316                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
11317                 break;
11318                 case "tr":
11319                     st.left = st.bottom = "0";
11320                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
11321                 break;
11322             }
11323
11324             arguments.callee.anim = wrap.fxanim(a,
11325                 o,
11326                 'motion',
11327                 .5,
11328                 "easeOut", after);
11329         });
11330         return this;
11331     },
11332
11333         /**
11334          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
11335          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
11336          * The element must be removed from the DOM using the 'remove' config option if desired.
11337          * Usage:
11338          *<pre><code>
11339 // default
11340 el.puff();
11341
11342 // common config options shown with default values
11343 el.puff({
11344     easing: 'easeOut',
11345     duration: .5,
11346     remove: false,
11347     useDisplay: false
11348 });
11349 </code></pre>
11350          * @param {Object} options (optional) Object literal with any of the Fx config options
11351          * @return {Roo.Element} The Element
11352          */
11353     puff : function(o){
11354         var el = this.getFxEl();
11355         o = o || {};
11356
11357         el.queueFx(o, function(){
11358             this.clearOpacity();
11359             this.show();
11360
11361             // restore values after effect
11362             var r = this.getFxRestore();
11363             var st = this.dom.style;
11364
11365             var after = function(){
11366                 if(o.useDisplay){
11367                     el.setDisplayed(false);
11368                 }else{
11369                     el.hide();
11370                 }
11371
11372                 el.clearOpacity();
11373
11374                 el.setPositioning(r.pos);
11375                 st.width = r.width;
11376                 st.height = r.height;
11377                 st.fontSize = '';
11378                 el.afterFx(o);
11379             };
11380
11381             var width = this.getWidth();
11382             var height = this.getHeight();
11383
11384             arguments.callee.anim = this.fxanim({
11385                     width : {to: this.adjustWidth(width * 2)},
11386                     height : {to: this.adjustHeight(height * 2)},
11387                     points : {by: [-(width * .5), -(height * .5)]},
11388                     opacity : {to: 0},
11389                     fontSize: {to:200, unit: "%"}
11390                 },
11391                 o,
11392                 'motion',
11393                 .5,
11394                 "easeOut", after);
11395         });
11396         return this;
11397     },
11398
11399         /**
11400          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
11401          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
11402          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
11403          * Usage:
11404          *<pre><code>
11405 // default
11406 el.switchOff();
11407
11408 // all config options shown with default values
11409 el.switchOff({
11410     easing: 'easeIn',
11411     duration: .3,
11412     remove: false,
11413     useDisplay: false
11414 });
11415 </code></pre>
11416          * @param {Object} options (optional) Object literal with any of the Fx config options
11417          * @return {Roo.Element} The Element
11418          */
11419     switchOff : function(o){
11420         var el = this.getFxEl();
11421         o = o || {};
11422
11423         el.queueFx(o, function(){
11424             this.clearOpacity();
11425             this.clip();
11426
11427             // restore values after effect
11428             var r = this.getFxRestore();
11429             var st = this.dom.style;
11430
11431             var after = function(){
11432                 if(o.useDisplay){
11433                     el.setDisplayed(false);
11434                 }else{
11435                     el.hide();
11436                 }
11437
11438                 el.clearOpacity();
11439                 el.setPositioning(r.pos);
11440                 st.width = r.width;
11441                 st.height = r.height;
11442
11443                 el.afterFx(o);
11444             };
11445
11446             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
11447                 this.clearOpacity();
11448                 (function(){
11449                     this.fxanim({
11450                         height:{to:1},
11451                         points:{by:[0, this.getHeight() * .5]}
11452                     }, o, 'motion', 0.3, 'easeIn', after);
11453                 }).defer(100, this);
11454             });
11455         });
11456         return this;
11457     },
11458
11459     /**
11460      * Highlights the Element by setting a color (applies to the background-color by default, but can be
11461      * changed using the "attr" config option) and then fading back to the original color. If no original
11462      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
11463      * Usage:
11464 <pre><code>
11465 // default: highlight background to yellow
11466 el.highlight();
11467
11468 // custom: highlight foreground text to blue for 2 seconds
11469 el.highlight("0000ff", { attr: 'color', duration: 2 });
11470
11471 // common config options shown with default values
11472 el.highlight("ffff9c", {
11473     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
11474     endColor: (current color) or "ffffff",
11475     easing: 'easeIn',
11476     duration: 1
11477 });
11478 </code></pre>
11479      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
11480      * @param {Object} options (optional) Object literal with any of the Fx config options
11481      * @return {Roo.Element} The Element
11482      */ 
11483     highlight : function(color, o){
11484         var el = this.getFxEl();
11485         o = o || {};
11486
11487         el.queueFx(o, function(){
11488             color = color || "ffff9c";
11489             attr = o.attr || "backgroundColor";
11490
11491             this.clearOpacity();
11492             this.show();
11493
11494             var origColor = this.getColor(attr);
11495             var restoreColor = this.dom.style[attr];
11496             endColor = (o.endColor || origColor) || "ffffff";
11497
11498             var after = function(){
11499                 el.dom.style[attr] = restoreColor;
11500                 el.afterFx(o);
11501             };
11502
11503             var a = {};
11504             a[attr] = {from: color, to: endColor};
11505             arguments.callee.anim = this.fxanim(a,
11506                 o,
11507                 'color',
11508                 1,
11509                 'easeIn', after);
11510         });
11511         return this;
11512     },
11513
11514    /**
11515     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
11516     * Usage:
11517 <pre><code>
11518 // default: a single light blue ripple
11519 el.frame();
11520
11521 // custom: 3 red ripples lasting 3 seconds total
11522 el.frame("ff0000", 3, { duration: 3 });
11523
11524 // common config options shown with default values
11525 el.frame("C3DAF9", 1, {
11526     duration: 1 //duration of entire animation (not each individual ripple)
11527     // Note: Easing is not configurable and will be ignored if included
11528 });
11529 </code></pre>
11530     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
11531     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
11532     * @param {Object} options (optional) Object literal with any of the Fx config options
11533     * @return {Roo.Element} The Element
11534     */
11535     frame : function(color, count, o){
11536         var el = this.getFxEl();
11537         o = o || {};
11538
11539         el.queueFx(o, function(){
11540             color = color || "#C3DAF9";
11541             if(color.length == 6){
11542                 color = "#" + color;
11543             }
11544             count = count || 1;
11545             duration = o.duration || 1;
11546             this.show();
11547
11548             var b = this.getBox();
11549             var animFn = function(){
11550                 var proxy = this.createProxy({
11551
11552                      style:{
11553                         visbility:"hidden",
11554                         position:"absolute",
11555                         "z-index":"35000", // yee haw
11556                         border:"0px solid " + color
11557                      }
11558                   });
11559                 var scale = Roo.isBorderBox ? 2 : 1;
11560                 proxy.animate({
11561                     top:{from:b.y, to:b.y - 20},
11562                     left:{from:b.x, to:b.x - 20},
11563                     borderWidth:{from:0, to:10},
11564                     opacity:{from:1, to:0},
11565                     height:{from:b.height, to:(b.height + (20*scale))},
11566                     width:{from:b.width, to:(b.width + (20*scale))}
11567                 }, duration, function(){
11568                     proxy.remove();
11569                 });
11570                 if(--count > 0){
11571                      animFn.defer((duration/2)*1000, this);
11572                 }else{
11573                     el.afterFx(o);
11574                 }
11575             };
11576             animFn.call(this);
11577         });
11578         return this;
11579     },
11580
11581    /**
11582     * Creates a pause before any subsequent queued effects begin.  If there are
11583     * no effects queued after the pause it will have no effect.
11584     * Usage:
11585 <pre><code>
11586 el.pause(1);
11587 </code></pre>
11588     * @param {Number} seconds The length of time to pause (in seconds)
11589     * @return {Roo.Element} The Element
11590     */
11591     pause : function(seconds){
11592         var el = this.getFxEl();
11593         var o = {};
11594
11595         el.queueFx(o, function(){
11596             setTimeout(function(){
11597                 el.afterFx(o);
11598             }, seconds * 1000);
11599         });
11600         return this;
11601     },
11602
11603    /**
11604     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
11605     * using the "endOpacity" config option.
11606     * Usage:
11607 <pre><code>
11608 // default: fade in from opacity 0 to 100%
11609 el.fadeIn();
11610
11611 // custom: fade in from opacity 0 to 75% over 2 seconds
11612 el.fadeIn({ endOpacity: .75, duration: 2});
11613
11614 // common config options shown with default values
11615 el.fadeIn({
11616     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
11617     easing: 'easeOut',
11618     duration: .5
11619 });
11620 </code></pre>
11621     * @param {Object} options (optional) Object literal with any of the Fx config options
11622     * @return {Roo.Element} The Element
11623     */
11624     fadeIn : function(o){
11625         var el = this.getFxEl();
11626         o = o || {};
11627         el.queueFx(o, function(){
11628             this.setOpacity(0);
11629             this.fixDisplay();
11630             this.dom.style.visibility = 'visible';
11631             var to = o.endOpacity || 1;
11632             arguments.callee.anim = this.fxanim({opacity:{to:to}},
11633                 o, null, .5, "easeOut", function(){
11634                 if(to == 1){
11635                     this.clearOpacity();
11636                 }
11637                 el.afterFx(o);
11638             });
11639         });
11640         return this;
11641     },
11642
11643    /**
11644     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
11645     * using the "endOpacity" config option.
11646     * Usage:
11647 <pre><code>
11648 // default: fade out from the element's current opacity to 0
11649 el.fadeOut();
11650
11651 // custom: fade out from the element's current opacity to 25% over 2 seconds
11652 el.fadeOut({ endOpacity: .25, duration: 2});
11653
11654 // common config options shown with default values
11655 el.fadeOut({
11656     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
11657     easing: 'easeOut',
11658     duration: .5
11659     remove: false,
11660     useDisplay: false
11661 });
11662 </code></pre>
11663     * @param {Object} options (optional) Object literal with any of the Fx config options
11664     * @return {Roo.Element} The Element
11665     */
11666     fadeOut : function(o){
11667         var el = this.getFxEl();
11668         o = o || {};
11669         el.queueFx(o, function(){
11670             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
11671                 o, null, .5, "easeOut", function(){
11672                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
11673                      this.dom.style.display = "none";
11674                 }else{
11675                      this.dom.style.visibility = "hidden";
11676                 }
11677                 this.clearOpacity();
11678                 el.afterFx(o);
11679             });
11680         });
11681         return this;
11682     },
11683
11684    /**
11685     * Animates the transition of an element's dimensions from a starting height/width
11686     * to an ending height/width.
11687     * Usage:
11688 <pre><code>
11689 // change height and width to 100x100 pixels
11690 el.scale(100, 100);
11691
11692 // common config options shown with default values.  The height and width will default to
11693 // the element's existing values if passed as null.
11694 el.scale(
11695     [element's width],
11696     [element's height], {
11697     easing: 'easeOut',
11698     duration: .35
11699 });
11700 </code></pre>
11701     * @param {Number} width  The new width (pass undefined to keep the original width)
11702     * @param {Number} height  The new height (pass undefined to keep the original height)
11703     * @param {Object} options (optional) Object literal with any of the Fx config options
11704     * @return {Roo.Element} The Element
11705     */
11706     scale : function(w, h, o){
11707         this.shift(Roo.apply({}, o, {
11708             width: w,
11709             height: h
11710         }));
11711         return this;
11712     },
11713
11714    /**
11715     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
11716     * Any of these properties not specified in the config object will not be changed.  This effect 
11717     * requires that at least one new dimension, position or opacity setting must be passed in on
11718     * the config object in order for the function to have any effect.
11719     * Usage:
11720 <pre><code>
11721 // slide the element horizontally to x position 200 while changing the height and opacity
11722 el.shift({ x: 200, height: 50, opacity: .8 });
11723
11724 // common config options shown with default values.
11725 el.shift({
11726     width: [element's width],
11727     height: [element's height],
11728     x: [element's x position],
11729     y: [element's y position],
11730     opacity: [element's opacity],
11731     easing: 'easeOut',
11732     duration: .35
11733 });
11734 </code></pre>
11735     * @param {Object} options  Object literal with any of the Fx config options
11736     * @return {Roo.Element} The Element
11737     */
11738     shift : function(o){
11739         var el = this.getFxEl();
11740         o = o || {};
11741         el.queueFx(o, function(){
11742             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
11743             if(w !== undefined){
11744                 a.width = {to: this.adjustWidth(w)};
11745             }
11746             if(h !== undefined){
11747                 a.height = {to: this.adjustHeight(h)};
11748             }
11749             if(x !== undefined || y !== undefined){
11750                 a.points = {to: [
11751                     x !== undefined ? x : this.getX(),
11752                     y !== undefined ? y : this.getY()
11753                 ]};
11754             }
11755             if(op !== undefined){
11756                 a.opacity = {to: op};
11757             }
11758             if(o.xy !== undefined){
11759                 a.points = {to: o.xy};
11760             }
11761             arguments.callee.anim = this.fxanim(a,
11762                 o, 'motion', .35, "easeOut", function(){
11763                 el.afterFx(o);
11764             });
11765         });
11766         return this;
11767     },
11768
11769         /**
11770          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
11771          * ending point of the effect.
11772          * Usage:
11773          *<pre><code>
11774 // default: slide the element downward while fading out
11775 el.ghost();
11776
11777 // custom: slide the element out to the right with a 2-second duration
11778 el.ghost('r', { duration: 2 });
11779
11780 // common config options shown with default values
11781 el.ghost('b', {
11782     easing: 'easeOut',
11783     duration: .5
11784     remove: false,
11785     useDisplay: false
11786 });
11787 </code></pre>
11788          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
11789          * @param {Object} options (optional) Object literal with any of the Fx config options
11790          * @return {Roo.Element} The Element
11791          */
11792     ghost : function(anchor, o){
11793         var el = this.getFxEl();
11794         o = o || {};
11795
11796         el.queueFx(o, function(){
11797             anchor = anchor || "b";
11798
11799             // restore values after effect
11800             var r = this.getFxRestore();
11801             var w = this.getWidth(),
11802                 h = this.getHeight();
11803
11804             var st = this.dom.style;
11805
11806             var after = function(){
11807                 if(o.useDisplay){
11808                     el.setDisplayed(false);
11809                 }else{
11810                     el.hide();
11811                 }
11812
11813                 el.clearOpacity();
11814                 el.setPositioning(r.pos);
11815                 st.width = r.width;
11816                 st.height = r.height;
11817
11818                 el.afterFx(o);
11819             };
11820
11821             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
11822             switch(anchor.toLowerCase()){
11823                 case "t":
11824                     pt.by = [0, -h];
11825                 break;
11826                 case "l":
11827                     pt.by = [-w, 0];
11828                 break;
11829                 case "r":
11830                     pt.by = [w, 0];
11831                 break;
11832                 case "b":
11833                     pt.by = [0, h];
11834                 break;
11835                 case "tl":
11836                     pt.by = [-w, -h];
11837                 break;
11838                 case "bl":
11839                     pt.by = [-w, h];
11840                 break;
11841                 case "br":
11842                     pt.by = [w, h];
11843                 break;
11844                 case "tr":
11845                     pt.by = [w, -h];
11846                 break;
11847             }
11848
11849             arguments.callee.anim = this.fxanim(a,
11850                 o,
11851                 'motion',
11852                 .5,
11853                 "easeOut", after);
11854         });
11855         return this;
11856     },
11857
11858         /**
11859          * Ensures that all effects queued after syncFx is called on the element are
11860          * run concurrently.  This is the opposite of {@link #sequenceFx}.
11861          * @return {Roo.Element} The Element
11862          */
11863     syncFx : function(){
11864         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
11865             block : false,
11866             concurrent : true,
11867             stopFx : false
11868         });
11869         return this;
11870     },
11871
11872         /**
11873          * Ensures that all effects queued after sequenceFx is called on the element are
11874          * run in sequence.  This is the opposite of {@link #syncFx}.
11875          * @return {Roo.Element} The Element
11876          */
11877     sequenceFx : function(){
11878         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
11879             block : false,
11880             concurrent : false,
11881             stopFx : false
11882         });
11883         return this;
11884     },
11885
11886         /* @private */
11887     nextFx : function(){
11888         var ef = this.fxQueue[0];
11889         if(ef){
11890             ef.call(this);
11891         }
11892     },
11893
11894         /**
11895          * Returns true if the element has any effects actively running or queued, else returns false.
11896          * @return {Boolean} True if element has active effects, else false
11897          */
11898     hasActiveFx : function(){
11899         return this.fxQueue && this.fxQueue[0];
11900     },
11901
11902         /**
11903          * Stops any running effects and clears the element's internal effects queue if it contains
11904          * any additional effects that haven't started yet.
11905          * @return {Roo.Element} The Element
11906          */
11907     stopFx : function(){
11908         if(this.hasActiveFx()){
11909             var cur = this.fxQueue[0];
11910             if(cur && cur.anim && cur.anim.isAnimated()){
11911                 this.fxQueue = [cur]; // clear out others
11912                 cur.anim.stop(true);
11913             }
11914         }
11915         return this;
11916     },
11917
11918         /* @private */
11919     beforeFx : function(o){
11920         if(this.hasActiveFx() && !o.concurrent){
11921            if(o.stopFx){
11922                this.stopFx();
11923                return true;
11924            }
11925            return false;
11926         }
11927         return true;
11928     },
11929
11930         /**
11931          * Returns true if the element is currently blocking so that no other effect can be queued
11932          * until this effect is finished, else returns false if blocking is not set.  This is commonly
11933          * used to ensure that an effect initiated by a user action runs to completion prior to the
11934          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
11935          * @return {Boolean} True if blocking, else false
11936          */
11937     hasFxBlock : function(){
11938         var q = this.fxQueue;
11939         return q && q[0] && q[0].block;
11940     },
11941
11942         /* @private */
11943     queueFx : function(o, fn){
11944         if(!this.fxQueue){
11945             this.fxQueue = [];
11946         }
11947         if(!this.hasFxBlock()){
11948             Roo.applyIf(o, this.fxDefaults);
11949             if(!o.concurrent){
11950                 var run = this.beforeFx(o);
11951                 fn.block = o.block;
11952                 this.fxQueue.push(fn);
11953                 if(run){
11954                     this.nextFx();
11955                 }
11956             }else{
11957                 fn.call(this);
11958             }
11959         }
11960         return this;
11961     },
11962
11963         /* @private */
11964     fxWrap : function(pos, o, vis){
11965         var wrap;
11966         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
11967             var wrapXY;
11968             if(o.fixPosition){
11969                 wrapXY = this.getXY();
11970             }
11971             var div = document.createElement("div");
11972             div.style.visibility = vis;
11973             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
11974             wrap.setPositioning(pos);
11975             if(wrap.getStyle("position") == "static"){
11976                 wrap.position("relative");
11977             }
11978             this.clearPositioning('auto');
11979             wrap.clip();
11980             wrap.dom.appendChild(this.dom);
11981             if(wrapXY){
11982                 wrap.setXY(wrapXY);
11983             }
11984         }
11985         return wrap;
11986     },
11987
11988         /* @private */
11989     fxUnwrap : function(wrap, pos, o){
11990         this.clearPositioning();
11991         this.setPositioning(pos);
11992         if(!o.wrap){
11993             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
11994             wrap.remove();
11995         }
11996     },
11997
11998         /* @private */
11999     getFxRestore : function(){
12000         var st = this.dom.style;
12001         return {pos: this.getPositioning(), width: st.width, height : st.height};
12002     },
12003
12004         /* @private */
12005     afterFx : function(o){
12006         if(o.afterStyle){
12007             this.applyStyles(o.afterStyle);
12008         }
12009         if(o.afterCls){
12010             this.addClass(o.afterCls);
12011         }
12012         if(o.remove === true){
12013             this.remove();
12014         }
12015         Roo.callback(o.callback, o.scope, [this]);
12016         if(!o.concurrent){
12017             this.fxQueue.shift();
12018             this.nextFx();
12019         }
12020     },
12021
12022         /* @private */
12023     getFxEl : function(){ // support for composite element fx
12024         return Roo.get(this.dom);
12025     },
12026
12027         /* @private */
12028     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
12029         animType = animType || 'run';
12030         opt = opt || {};
12031         var anim = Roo.lib.Anim[animType](
12032             this.dom, args,
12033             (opt.duration || defaultDur) || .35,
12034             (opt.easing || defaultEase) || 'easeOut',
12035             function(){
12036                 Roo.callback(cb, this);
12037             },
12038             this
12039         );
12040         opt.anim = anim;
12041         return anim;
12042     }
12043 };
12044
12045 // backwords compat
12046 Roo.Fx.resize = Roo.Fx.scale;
12047
12048 //When included, Roo.Fx is automatically applied to Element so that all basic
12049 //effects are available directly via the Element API
12050 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
12051  * Based on:
12052  * Ext JS Library 1.1.1
12053  * Copyright(c) 2006-2007, Ext JS, LLC.
12054  *
12055  * Originally Released Under LGPL - original licence link has changed is not relivant.
12056  *
12057  * Fork - LGPL
12058  * <script type="text/javascript">
12059  */
12060
12061
12062 /**
12063  * @class Roo.CompositeElement
12064  * Standard composite class. Creates a Roo.Element for every element in the collection.
12065  * <br><br>
12066  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
12067  * actions will be performed on all the elements in this collection.</b>
12068  * <br><br>
12069  * All methods return <i>this</i> and can be chained.
12070  <pre><code>
12071  var els = Roo.select("#some-el div.some-class", true);
12072  // or select directly from an existing element
12073  var el = Roo.get('some-el');
12074  el.select('div.some-class', true);
12075
12076  els.setWidth(100); // all elements become 100 width
12077  els.hide(true); // all elements fade out and hide
12078  // or
12079  els.setWidth(100).hide(true);
12080  </code></pre>
12081  */
12082 Roo.CompositeElement = function(els){
12083     this.elements = [];
12084     this.addElements(els);
12085 };
12086 Roo.CompositeElement.prototype = {
12087     isComposite: true,
12088     addElements : function(els){
12089         if(!els) {
12090             return this;
12091         }
12092         if(typeof els == "string"){
12093             els = Roo.Element.selectorFunction(els);
12094         }
12095         var yels = this.elements;
12096         var index = yels.length-1;
12097         for(var i = 0, len = els.length; i < len; i++) {
12098                 yels[++index] = Roo.get(els[i]);
12099         }
12100         return this;
12101     },
12102
12103     /**
12104     * Clears this composite and adds the elements returned by the passed selector.
12105     * @param {String/Array} els A string CSS selector, an array of elements or an element
12106     * @return {CompositeElement} this
12107     */
12108     fill : function(els){
12109         this.elements = [];
12110         this.add(els);
12111         return this;
12112     },
12113
12114     /**
12115     * Filters this composite to only elements that match the passed selector.
12116     * @param {String} selector A string CSS selector
12117     * @param {Boolean} inverse return inverse filter (not matches)
12118     * @return {CompositeElement} this
12119     */
12120     filter : function(selector, inverse){
12121         var els = [];
12122         inverse = inverse || false;
12123         this.each(function(el){
12124             var match = inverse ? !el.is(selector) : el.is(selector);
12125             if(match){
12126                 els[els.length] = el.dom;
12127             }
12128         });
12129         this.fill(els);
12130         return this;
12131     },
12132
12133     invoke : function(fn, args){
12134         var els = this.elements;
12135         for(var i = 0, len = els.length; i < len; i++) {
12136                 Roo.Element.prototype[fn].apply(els[i], args);
12137         }
12138         return this;
12139     },
12140     /**
12141     * Adds elements to this composite.
12142     * @param {String/Array} els A string CSS selector, an array of elements or an element
12143     * @return {CompositeElement} this
12144     */
12145     add : function(els){
12146         if(typeof els == "string"){
12147             this.addElements(Roo.Element.selectorFunction(els));
12148         }else if(els.length !== undefined){
12149             this.addElements(els);
12150         }else{
12151             this.addElements([els]);
12152         }
12153         return this;
12154     },
12155     /**
12156     * Calls the passed function passing (el, this, index) for each element in this composite.
12157     * @param {Function} fn The function to call
12158     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
12159     * @return {CompositeElement} this
12160     */
12161     each : function(fn, scope){
12162         var els = this.elements;
12163         for(var i = 0, len = els.length; i < len; i++){
12164             if(fn.call(scope || els[i], els[i], this, i) === false) {
12165                 break;
12166             }
12167         }
12168         return this;
12169     },
12170
12171     /**
12172      * Returns the Element object at the specified index
12173      * @param {Number} index
12174      * @return {Roo.Element}
12175      */
12176     item : function(index){
12177         return this.elements[index] || null;
12178     },
12179
12180     /**
12181      * Returns the first Element
12182      * @return {Roo.Element}
12183      */
12184     first : function(){
12185         return this.item(0);
12186     },
12187
12188     /**
12189      * Returns the last Element
12190      * @return {Roo.Element}
12191      */
12192     last : function(){
12193         return this.item(this.elements.length-1);
12194     },
12195
12196     /**
12197      * Returns the number of elements in this composite
12198      * @return Number
12199      */
12200     getCount : function(){
12201         return this.elements.length;
12202     },
12203
12204     /**
12205      * Returns true if this composite contains the passed element
12206      * @return Boolean
12207      */
12208     contains : function(el){
12209         return this.indexOf(el) !== -1;
12210     },
12211
12212     /**
12213      * Returns true if this composite contains the passed element
12214      * @return Boolean
12215      */
12216     indexOf : function(el){
12217         return this.elements.indexOf(Roo.get(el));
12218     },
12219
12220
12221     /**
12222     * Removes the specified element(s).
12223     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
12224     * or an array of any of those.
12225     * @param {Boolean} removeDom (optional) True to also remove the element from the document
12226     * @return {CompositeElement} this
12227     */
12228     removeElement : function(el, removeDom){
12229         if(el instanceof Array){
12230             for(var i = 0, len = el.length; i < len; i++){
12231                 this.removeElement(el[i]);
12232             }
12233             return this;
12234         }
12235         var index = typeof el == 'number' ? el : this.indexOf(el);
12236         if(index !== -1){
12237             if(removeDom){
12238                 var d = this.elements[index];
12239                 if(d.dom){
12240                     d.remove();
12241                 }else{
12242                     d.parentNode.removeChild(d);
12243                 }
12244             }
12245             this.elements.splice(index, 1);
12246         }
12247         return this;
12248     },
12249
12250     /**
12251     * Replaces the specified element with the passed element.
12252     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
12253     * to replace.
12254     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
12255     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
12256     * @return {CompositeElement} this
12257     */
12258     replaceElement : function(el, replacement, domReplace){
12259         var index = typeof el == 'number' ? el : this.indexOf(el);
12260         if(index !== -1){
12261             if(domReplace){
12262                 this.elements[index].replaceWith(replacement);
12263             }else{
12264                 this.elements.splice(index, 1, Roo.get(replacement))
12265             }
12266         }
12267         return this;
12268     },
12269
12270     /**
12271      * Removes all elements.
12272      */
12273     clear : function(){
12274         this.elements = [];
12275     }
12276 };
12277 (function(){
12278     Roo.CompositeElement.createCall = function(proto, fnName){
12279         if(!proto[fnName]){
12280             proto[fnName] = function(){
12281                 return this.invoke(fnName, arguments);
12282             };
12283         }
12284     };
12285     for(var fnName in Roo.Element.prototype){
12286         if(typeof Roo.Element.prototype[fnName] == "function"){
12287             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
12288         }
12289     };
12290 })();
12291 /*
12292  * Based on:
12293  * Ext JS Library 1.1.1
12294  * Copyright(c) 2006-2007, Ext JS, LLC.
12295  *
12296  * Originally Released Under LGPL - original licence link has changed is not relivant.
12297  *
12298  * Fork - LGPL
12299  * <script type="text/javascript">
12300  */
12301
12302 /**
12303  * @class Roo.CompositeElementLite
12304  * @extends Roo.CompositeElement
12305  * Flyweight composite class. Reuses the same Roo.Element for element operations.
12306  <pre><code>
12307  var els = Roo.select("#some-el div.some-class");
12308  // or select directly from an existing element
12309  var el = Roo.get('some-el');
12310  el.select('div.some-class');
12311
12312  els.setWidth(100); // all elements become 100 width
12313  els.hide(true); // all elements fade out and hide
12314  // or
12315  els.setWidth(100).hide(true);
12316  </code></pre><br><br>
12317  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
12318  * actions will be performed on all the elements in this collection.</b>
12319  */
12320 Roo.CompositeElementLite = function(els){
12321     Roo.CompositeElementLite.superclass.constructor.call(this, els);
12322     this.el = new Roo.Element.Flyweight();
12323 };
12324 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
12325     addElements : function(els){
12326         if(els){
12327             if(els instanceof Array){
12328                 this.elements = this.elements.concat(els);
12329             }else{
12330                 var yels = this.elements;
12331                 var index = yels.length-1;
12332                 for(var i = 0, len = els.length; i < len; i++) {
12333                     yels[++index] = els[i];
12334                 }
12335             }
12336         }
12337         return this;
12338     },
12339     invoke : function(fn, args){
12340         var els = this.elements;
12341         var el = this.el;
12342         for(var i = 0, len = els.length; i < len; i++) {
12343             el.dom = els[i];
12344                 Roo.Element.prototype[fn].apply(el, args);
12345         }
12346         return this;
12347     },
12348     /**
12349      * Returns a flyweight Element of the dom element object at the specified index
12350      * @param {Number} index
12351      * @return {Roo.Element}
12352      */
12353     item : function(index){
12354         if(!this.elements[index]){
12355             return null;
12356         }
12357         this.el.dom = this.elements[index];
12358         return this.el;
12359     },
12360
12361     // fixes scope with flyweight
12362     addListener : function(eventName, handler, scope, opt){
12363         var els = this.elements;
12364         for(var i = 0, len = els.length; i < len; i++) {
12365             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
12366         }
12367         return this;
12368     },
12369
12370     /**
12371     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
12372     * passed is the flyweight (shared) Roo.Element instance, so if you require a
12373     * a reference to the dom node, use el.dom.</b>
12374     * @param {Function} fn The function to call
12375     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
12376     * @return {CompositeElement} this
12377     */
12378     each : function(fn, scope){
12379         var els = this.elements;
12380         var el = this.el;
12381         for(var i = 0, len = els.length; i < len; i++){
12382             el.dom = els[i];
12383                 if(fn.call(scope || el, el, this, i) === false){
12384                 break;
12385             }
12386         }
12387         return this;
12388     },
12389
12390     indexOf : function(el){
12391         return this.elements.indexOf(Roo.getDom(el));
12392     },
12393
12394     replaceElement : function(el, replacement, domReplace){
12395         var index = typeof el == 'number' ? el : this.indexOf(el);
12396         if(index !== -1){
12397             replacement = Roo.getDom(replacement);
12398             if(domReplace){
12399                 var d = this.elements[index];
12400                 d.parentNode.insertBefore(replacement, d);
12401                 d.parentNode.removeChild(d);
12402             }
12403             this.elements.splice(index, 1, replacement);
12404         }
12405         return this;
12406     }
12407 });
12408 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
12409
12410 /*
12411  * Based on:
12412  * Ext JS Library 1.1.1
12413  * Copyright(c) 2006-2007, Ext JS, LLC.
12414  *
12415  * Originally Released Under LGPL - original licence link has changed is not relivant.
12416  *
12417  * Fork - LGPL
12418  * <script type="text/javascript">
12419  */
12420
12421  
12422
12423 /**
12424  * @class Roo.data.Connection
12425  * @extends Roo.util.Observable
12426  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
12427  * either to a configured URL, or to a URL specified at request time. 
12428  * 
12429  * Requests made by this class are asynchronous, and will return immediately. No data from
12430  * the server will be available to the statement immediately following the {@link #request} call.
12431  * To process returned data, use a callback in the request options object, or an event listener.
12432  * 
12433  * Note: If you are doing a file upload, you will not get a normal response object sent back to
12434  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
12435  * The response object is created using the innerHTML of the IFRAME's document as the responseText
12436  * property and, if present, the IFRAME's XML document as the responseXML property.
12437  * 
12438  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
12439  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
12440  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
12441  * standard DOM methods.
12442  * @constructor
12443  * @param {Object} config a configuration object.
12444  */
12445 Roo.data.Connection = function(config){
12446     Roo.apply(this, config);
12447     this.addEvents({
12448         /**
12449          * @event beforerequest
12450          * Fires before a network request is made to retrieve a data object.
12451          * @param {Connection} conn This Connection object.
12452          * @param {Object} options The options config object passed to the {@link #request} method.
12453          */
12454         "beforerequest" : true,
12455         /**
12456          * @event requestcomplete
12457          * Fires if the request was successfully completed.
12458          * @param {Connection} conn This Connection object.
12459          * @param {Object} response The XHR object containing the response data.
12460          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
12461          * @param {Object} options The options config object passed to the {@link #request} method.
12462          */
12463         "requestcomplete" : true,
12464         /**
12465          * @event requestexception
12466          * Fires if an error HTTP status was returned from the server.
12467          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
12468          * @param {Connection} conn This Connection object.
12469          * @param {Object} response The XHR object containing the response data.
12470          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
12471          * @param {Object} options The options config object passed to the {@link #request} method.
12472          */
12473         "requestexception" : true
12474     });
12475     Roo.data.Connection.superclass.constructor.call(this);
12476 };
12477
12478 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
12479     /**
12480      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12481      */
12482     /**
12483      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12484      * extra parameters to each request made by this object. (defaults to undefined)
12485      */
12486     /**
12487      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12488      *  to each request made by this object. (defaults to undefined)
12489      */
12490     /**
12491      * @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)
12492      */
12493     /**
12494      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12495      */
12496     timeout : 30000,
12497     /**
12498      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12499      * @type Boolean
12500      */
12501     autoAbort:false,
12502
12503     /**
12504      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12505      * @type Boolean
12506      */
12507     disableCaching: true,
12508
12509     /**
12510      * Sends an HTTP request to a remote server.
12511      * @param {Object} options An object which may contain the following properties:<ul>
12512      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
12513      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
12514      * request, a url encoded string or a function to call to get either.</li>
12515      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
12516      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
12517      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
12518      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
12519      * <li>options {Object} The parameter to the request call.</li>
12520      * <li>success {Boolean} True if the request succeeded.</li>
12521      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
12522      * </ul></li>
12523      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
12524      * The callback is passed the following parameters:<ul>
12525      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
12526      * <li>options {Object} The parameter to the request call.</li>
12527      * </ul></li>
12528      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
12529      * The callback is passed the following parameters:<ul>
12530      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
12531      * <li>options {Object} The parameter to the request call.</li>
12532      * </ul></li>
12533      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
12534      * for the callback function. Defaults to the browser window.</li>
12535      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
12536      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
12537      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
12538      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
12539      * params for the post data. Any params will be appended to the URL.</li>
12540      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
12541      * </ul>
12542      * @return {Number} transactionId
12543      */
12544     request : function(o){
12545         if(this.fireEvent("beforerequest", this, o) !== false){
12546             var p = o.params;
12547
12548             if(typeof p == "function"){
12549                 p = p.call(o.scope||window, o);
12550             }
12551             if(typeof p == "object"){
12552                 p = Roo.urlEncode(o.params);
12553             }
12554             if(this.extraParams){
12555                 var extras = Roo.urlEncode(this.extraParams);
12556                 p = p ? (p + '&' + extras) : extras;
12557             }
12558
12559             var url = o.url || this.url;
12560             if(typeof url == 'function'){
12561                 url = url.call(o.scope||window, o);
12562             }
12563
12564             if(o.form){
12565                 var form = Roo.getDom(o.form);
12566                 url = url || form.action;
12567
12568                 var enctype = form.getAttribute("enctype");
12569                 
12570                 if (o.formData) {
12571                     return this.doFormDataUpload(o, url);
12572                 }
12573                 
12574                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
12575                     return this.doFormUpload(o, p, url);
12576                 }
12577                 var f = Roo.lib.Ajax.serializeForm(form);
12578                 p = p ? (p + '&' + f) : f;
12579             }
12580             
12581             if (!o.form && o.formData) {
12582                 o.formData = o.formData === true ? new FormData() : o.formData;
12583                 for (var k in o.params) {
12584                     o.formData.append(k,o.params[k]);
12585                 }
12586                     
12587                 return this.doFormDataUpload(o, url);
12588             }
12589             
12590
12591             var hs = o.headers;
12592             if(this.defaultHeaders){
12593                 hs = Roo.apply(hs || {}, this.defaultHeaders);
12594                 if(!o.headers){
12595                     o.headers = hs;
12596                 }
12597             }
12598
12599             var cb = {
12600                 success: this.handleResponse,
12601                 failure: this.handleFailure,
12602                 scope: this,
12603                 argument: {options: o},
12604                 timeout : o.timeout || this.timeout
12605             };
12606
12607             var method = o.method||this.method||(p ? "POST" : "GET");
12608
12609             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
12610                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
12611             }
12612
12613             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
12614                 if(o.autoAbort){
12615                     this.abort();
12616                 }
12617             }else if(this.autoAbort !== false){
12618                 this.abort();
12619             }
12620
12621             if((method == 'GET' && p) || o.xmlData){
12622                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
12623                 p = '';
12624             }
12625             Roo.lib.Ajax.useDefaultHeader = typeof(o.headers) == 'undefined' || typeof(o.headers['Content-Type']) == 'undefined';
12626             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
12627             Roo.lib.Ajax.useDefaultHeader == true;
12628             return this.transId;
12629         }else{
12630             Roo.callback(o.callback, o.scope, [o, null, null]);
12631             return null;
12632         }
12633     },
12634
12635     /**
12636      * Determine whether this object has a request outstanding.
12637      * @param {Number} transactionId (Optional) defaults to the last transaction
12638      * @return {Boolean} True if there is an outstanding request.
12639      */
12640     isLoading : function(transId){
12641         if(transId){
12642             return Roo.lib.Ajax.isCallInProgress(transId);
12643         }else{
12644             return this.transId ? true : false;
12645         }
12646     },
12647
12648     /**
12649      * Aborts any outstanding request.
12650      * @param {Number} transactionId (Optional) defaults to the last transaction
12651      */
12652     abort : function(transId){
12653         if(transId || this.isLoading()){
12654             Roo.lib.Ajax.abort(transId || this.transId);
12655         }
12656     },
12657
12658     // private
12659     handleResponse : function(response){
12660         this.transId = false;
12661         var options = response.argument.options;
12662         response.argument = options ? options.argument : null;
12663         this.fireEvent("requestcomplete", this, response, options);
12664         Roo.callback(options.success, options.scope, [response, options]);
12665         Roo.callback(options.callback, options.scope, [options, true, response]);
12666     },
12667
12668     // private
12669     handleFailure : function(response, e){
12670         this.transId = false;
12671         var options = response.argument.options;
12672         response.argument = options ? options.argument : null;
12673         this.fireEvent("requestexception", this, response, options, e);
12674         Roo.callback(options.failure, options.scope, [response, options]);
12675         Roo.callback(options.callback, options.scope, [options, false, response]);
12676     },
12677
12678     // private
12679     doFormUpload : function(o, ps, url){
12680         var id = Roo.id();
12681         var frame = document.createElement('iframe');
12682         frame.id = id;
12683         frame.name = id;
12684         frame.className = 'x-hidden';
12685         if(Roo.isIE){
12686             frame.src = Roo.SSL_SECURE_URL;
12687         }
12688         document.body.appendChild(frame);
12689
12690         if(Roo.isIE){
12691            document.frames[id].name = id;
12692         }
12693
12694         var form = Roo.getDom(o.form);
12695         form.target = id;
12696         form.method = 'POST';
12697         form.enctype = form.encoding = 'multipart/form-data';
12698         if(url){
12699             form.action = url;
12700         }
12701
12702         var hiddens, hd;
12703         if(ps){ // add dynamic params
12704             hiddens = [];
12705             ps = Roo.urlDecode(ps, false);
12706             for(var k in ps){
12707                 if(ps.hasOwnProperty(k)){
12708                     hd = document.createElement('input');
12709                     hd.type = 'hidden';
12710                     hd.name = k;
12711                     hd.value = ps[k];
12712                     form.appendChild(hd);
12713                     hiddens.push(hd);
12714                 }
12715             }
12716         }
12717
12718         function cb(){
12719             var r = {  // bogus response object
12720                 responseText : '',
12721                 responseXML : null
12722             };
12723
12724             r.argument = o ? o.argument : null;
12725
12726             try { //
12727                 var doc;
12728                 if(Roo.isIE){
12729                     doc = frame.contentWindow.document;
12730                 }else {
12731                     doc = (frame.contentDocument || window.frames[id].document);
12732                 }
12733                 if(doc && doc.body){
12734                     r.responseText = doc.body.innerHTML;
12735                 }
12736                 if(doc && doc.XMLDocument){
12737                     r.responseXML = doc.XMLDocument;
12738                 }else {
12739                     r.responseXML = doc;
12740                 }
12741             }
12742             catch(e) {
12743                 // ignore
12744             }
12745
12746             Roo.EventManager.removeListener(frame, 'load', cb, this);
12747
12748             this.fireEvent("requestcomplete", this, r, o);
12749             Roo.callback(o.success, o.scope, [r, o]);
12750             Roo.callback(o.callback, o.scope, [o, true, r]);
12751
12752             setTimeout(function(){document.body.removeChild(frame);}, 100);
12753         }
12754
12755         Roo.EventManager.on(frame, 'load', cb, this);
12756         form.submit();
12757
12758         if(hiddens){ // remove dynamic params
12759             for(var i = 0, len = hiddens.length; i < len; i++){
12760                 form.removeChild(hiddens[i]);
12761             }
12762         }
12763     },
12764     // this is a 'formdata version???'
12765     
12766     
12767     doFormDataUpload : function(o,  url)
12768     {
12769         var formData;
12770         if (o.form) {
12771             var form =  Roo.getDom(o.form);
12772             form.enctype = form.encoding = 'multipart/form-data';
12773             formData = o.formData === true ? new FormData(form) : o.formData;
12774         } else {
12775             formData = o.formData === true ? new FormData() : o.formData;
12776         }
12777         
12778       
12779         var cb = {
12780             success: this.handleResponse,
12781             failure: this.handleFailure,
12782             scope: this,
12783             argument: {options: o},
12784             timeout : o.timeout || this.timeout
12785         };
12786  
12787         if(typeof o.autoAbort == 'boolean'){ // options gets top priority
12788             if(o.autoAbort){
12789                 this.abort();
12790             }
12791         }else if(this.autoAbort !== false){
12792             this.abort();
12793         }
12794
12795         //Roo.lib.Ajax.defaultPostHeader = null;
12796         Roo.lib.Ajax.useDefaultHeader = false;
12797         this.transId = Roo.lib.Ajax.request( "POST", url, cb,  formData, o);
12798         Roo.lib.Ajax.useDefaultHeader = true;
12799  
12800          
12801     }
12802     
12803 });
12804 /*
12805  * Based on:
12806  * Ext JS Library 1.1.1
12807  * Copyright(c) 2006-2007, Ext JS, LLC.
12808  *
12809  * Originally Released Under LGPL - original licence link has changed is not relivant.
12810  *
12811  * Fork - LGPL
12812  * <script type="text/javascript">
12813  */
12814  
12815 /**
12816  * Global Ajax request class.
12817  * 
12818  * @class Roo.Ajax
12819  * @extends Roo.data.Connection
12820  * @static
12821  * 
12822  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
12823  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
12824  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
12825  * @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)
12826  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12827  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
12828  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
12829  */
12830 Roo.Ajax = new Roo.data.Connection({
12831     // fix up the docs
12832     /**
12833      * @scope Roo.Ajax
12834      * @type {Boolear} 
12835      */
12836     autoAbort : false,
12837
12838     /**
12839      * Serialize the passed form into a url encoded string
12840      * @scope Roo.Ajax
12841      * @param {String/HTMLElement} form
12842      * @return {String}
12843      */
12844     serializeForm : function(form){
12845         return Roo.lib.Ajax.serializeForm(form);
12846     }
12847 });/*
12848  * Based on:
12849  * Ext JS Library 1.1.1
12850  * Copyright(c) 2006-2007, Ext JS, LLC.
12851  *
12852  * Originally Released Under LGPL - original licence link has changed is not relivant.
12853  *
12854  * Fork - LGPL
12855  * <script type="text/javascript">
12856  */
12857
12858  
12859 /**
12860  * @class Roo.UpdateManager
12861  * @extends Roo.util.Observable
12862  * Provides AJAX-style update for Element object.<br><br>
12863  * Usage:<br>
12864  * <pre><code>
12865  * // Get it from a Roo.Element object
12866  * var el = Roo.get("foo");
12867  * var mgr = el.getUpdateManager();
12868  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
12869  * ...
12870  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
12871  * <br>
12872  * // or directly (returns the same UpdateManager instance)
12873  * var mgr = new Roo.UpdateManager("myElementId");
12874  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
12875  * mgr.on("update", myFcnNeedsToKnow);
12876  * <br>
12877    // short handed call directly from the element object
12878    Roo.get("foo").load({
12879         url: "bar.php",
12880         scripts:true,
12881         params: "for=bar",
12882         text: "Loading Foo..."
12883    });
12884  * </code></pre>
12885  * @constructor
12886  * Create new UpdateManager directly.
12887  * @param {String/HTMLElement/Roo.Element} el The element to update
12888  * @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).
12889  */
12890 Roo.UpdateManager = function(el, forceNew){
12891     el = Roo.get(el);
12892     if(!forceNew && el.updateManager){
12893         return el.updateManager;
12894     }
12895     /**
12896      * The Element object
12897      * @type Roo.Element
12898      */
12899     this.el = el;
12900     /**
12901      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
12902      * @type String
12903      */
12904     this.defaultUrl = null;
12905
12906     this.addEvents({
12907         /**
12908          * @event beforeupdate
12909          * Fired before an update is made, return false from your handler and the update is cancelled.
12910          * @param {Roo.Element} el
12911          * @param {String/Object/Function} url
12912          * @param {String/Object} params
12913          */
12914         "beforeupdate": true,
12915         /**
12916          * @event update
12917          * Fired after successful update is made.
12918          * @param {Roo.Element} el
12919          * @param {Object} oResponseObject The response Object
12920          */
12921         "update": true,
12922         /**
12923          * @event failure
12924          * Fired on update failure.
12925          * @param {Roo.Element} el
12926          * @param {Object} oResponseObject The response Object
12927          */
12928         "failure": true
12929     });
12930     var d = Roo.UpdateManager.defaults;
12931     /**
12932      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
12933      * @type String
12934      */
12935     this.sslBlankUrl = d.sslBlankUrl;
12936     /**
12937      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
12938      * @type Boolean
12939      */
12940     this.disableCaching = d.disableCaching;
12941     /**
12942      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
12943      * @type String
12944      */
12945     this.indicatorText = d.indicatorText;
12946     /**
12947      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
12948      * @type String
12949      */
12950     this.showLoadIndicator = d.showLoadIndicator;
12951     /**
12952      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
12953      * @type Number
12954      */
12955     this.timeout = d.timeout;
12956
12957     /**
12958      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
12959      * @type Boolean
12960      */
12961     this.loadScripts = d.loadScripts;
12962
12963     /**
12964      * Transaction object of current executing transaction
12965      */
12966     this.transaction = null;
12967
12968     /**
12969      * @private
12970      */
12971     this.autoRefreshProcId = null;
12972     /**
12973      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
12974      * @type Function
12975      */
12976     this.refreshDelegate = this.refresh.createDelegate(this);
12977     /**
12978      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
12979      * @type Function
12980      */
12981     this.updateDelegate = this.update.createDelegate(this);
12982     /**
12983      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
12984      * @type Function
12985      */
12986     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
12987     /**
12988      * @private
12989      */
12990     this.successDelegate = this.processSuccess.createDelegate(this);
12991     /**
12992      * @private
12993      */
12994     this.failureDelegate = this.processFailure.createDelegate(this);
12995
12996     if(!this.renderer){
12997      /**
12998       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
12999       */
13000     this.renderer = new Roo.UpdateManager.BasicRenderer();
13001     }
13002     
13003     Roo.UpdateManager.superclass.constructor.call(this);
13004 };
13005
13006 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
13007     /**
13008      * Get the Element this UpdateManager is bound to
13009      * @return {Roo.Element} The element
13010      */
13011     getEl : function(){
13012         return this.el;
13013     },
13014     /**
13015      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
13016      * @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:
13017 <pre><code>
13018 um.update({<br/>
13019     url: "your-url.php",<br/>
13020     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
13021     callback: yourFunction,<br/>
13022     scope: yourObject, //(optional scope)  <br/>
13023     discardUrl: false, <br/>
13024     nocache: false,<br/>
13025     text: "Loading...",<br/>
13026     timeout: 30,<br/>
13027     scripts: false<br/>
13028 });
13029 </code></pre>
13030      * The only required property is url. The optional properties nocache, text and scripts
13031      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
13032      * @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}
13033      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
13034      * @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.
13035      */
13036     update : function(url, params, callback, discardUrl){
13037         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
13038             var method = this.method,
13039                 cfg;
13040             if(typeof url == "object"){ // must be config object
13041                 cfg = url;
13042                 url = cfg.url;
13043                 params = params || cfg.params;
13044                 callback = callback || cfg.callback;
13045                 discardUrl = discardUrl || cfg.discardUrl;
13046                 if(callback && cfg.scope){
13047                     callback = callback.createDelegate(cfg.scope);
13048                 }
13049                 if(typeof cfg.method != "undefined"){method = cfg.method;};
13050                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
13051                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
13052                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
13053                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
13054             }
13055             this.showLoading();
13056             if(!discardUrl){
13057                 this.defaultUrl = url;
13058             }
13059             if(typeof url == "function"){
13060                 url = url.call(this);
13061             }
13062
13063             method = method || (params ? "POST" : "GET");
13064             if(method == "GET"){
13065                 url = this.prepareUrl(url);
13066             }
13067
13068             var o = Roo.apply(cfg ||{}, {
13069                 url : url,
13070                 params: params,
13071                 success: this.successDelegate,
13072                 failure: this.failureDelegate,
13073                 callback: undefined,
13074                 timeout: (this.timeout*1000),
13075                 argument: {"url": url, "form": null, "callback": callback, "params": params}
13076             });
13077             Roo.log("updated manager called with timeout of " + o.timeout);
13078             this.transaction = Roo.Ajax.request(o);
13079         }
13080     },
13081
13082     /**
13083      * 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.
13084      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
13085      * @param {String/HTMLElement} form The form Id or form element
13086      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
13087      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
13088      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
13089      */
13090     formUpdate : function(form, url, reset, callback){
13091         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
13092             if(typeof url == "function"){
13093                 url = url.call(this);
13094             }
13095             form = Roo.getDom(form);
13096             this.transaction = Roo.Ajax.request({
13097                 form: form,
13098                 url:url,
13099                 success: this.successDelegate,
13100                 failure: this.failureDelegate,
13101                 timeout: (this.timeout*1000),
13102                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
13103             });
13104             this.showLoading.defer(1, this);
13105         }
13106     },
13107
13108     /**
13109      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
13110      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
13111      */
13112     refresh : function(callback){
13113         if(this.defaultUrl == null){
13114             return;
13115         }
13116         this.update(this.defaultUrl, null, callback, true);
13117     },
13118
13119     /**
13120      * Set this element to auto refresh.
13121      * @param {Number} interval How often to update (in seconds).
13122      * @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)
13123      * @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}
13124      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
13125      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
13126      */
13127     startAutoRefresh : function(interval, url, params, callback, refreshNow){
13128         if(refreshNow){
13129             this.update(url || this.defaultUrl, params, callback, true);
13130         }
13131         if(this.autoRefreshProcId){
13132             clearInterval(this.autoRefreshProcId);
13133         }
13134         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
13135     },
13136
13137     /**
13138      * Stop auto refresh on this element.
13139      */
13140      stopAutoRefresh : function(){
13141         if(this.autoRefreshProcId){
13142             clearInterval(this.autoRefreshProcId);
13143             delete this.autoRefreshProcId;
13144         }
13145     },
13146
13147     isAutoRefreshing : function(){
13148        return this.autoRefreshProcId ? true : false;
13149     },
13150     /**
13151      * Called to update the element to "Loading" state. Override to perform custom action.
13152      */
13153     showLoading : function(){
13154         if(this.showLoadIndicator){
13155             this.el.update(this.indicatorText);
13156         }
13157     },
13158
13159     /**
13160      * Adds unique parameter to query string if disableCaching = true
13161      * @private
13162      */
13163     prepareUrl : function(url){
13164         if(this.disableCaching){
13165             var append = "_dc=" + (new Date().getTime());
13166             if(url.indexOf("?") !== -1){
13167                 url += "&" + append;
13168             }else{
13169                 url += "?" + append;
13170             }
13171         }
13172         return url;
13173     },
13174
13175     /**
13176      * @private
13177      */
13178     processSuccess : function(response){
13179         this.transaction = null;
13180         if(response.argument.form && response.argument.reset){
13181             try{ // put in try/catch since some older FF releases had problems with this
13182                 response.argument.form.reset();
13183             }catch(e){}
13184         }
13185         if(this.loadScripts){
13186             this.renderer.render(this.el, response, this,
13187                 this.updateComplete.createDelegate(this, [response]));
13188         }else{
13189             this.renderer.render(this.el, response, this);
13190             this.updateComplete(response);
13191         }
13192     },
13193
13194     updateComplete : function(response){
13195         this.fireEvent("update", this.el, response);
13196         if(typeof response.argument.callback == "function"){
13197             response.argument.callback(this.el, true, response);
13198         }
13199     },
13200
13201     /**
13202      * @private
13203      */
13204     processFailure : function(response){
13205         this.transaction = null;
13206         this.fireEvent("failure", this.el, response);
13207         if(typeof response.argument.callback == "function"){
13208             response.argument.callback(this.el, false, response);
13209         }
13210     },
13211
13212     /**
13213      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
13214      * @param {Object} renderer The object implementing the render() method
13215      */
13216     setRenderer : function(renderer){
13217         this.renderer = renderer;
13218     },
13219
13220     getRenderer : function(){
13221        return this.renderer;
13222     },
13223
13224     /**
13225      * Set the defaultUrl used for updates
13226      * @param {String/Function} defaultUrl The url or a function to call to get the url
13227      */
13228     setDefaultUrl : function(defaultUrl){
13229         this.defaultUrl = defaultUrl;
13230     },
13231
13232     /**
13233      * Aborts the executing transaction
13234      */
13235     abort : function(){
13236         if(this.transaction){
13237             Roo.Ajax.abort(this.transaction);
13238         }
13239     },
13240
13241     /**
13242      * Returns true if an update is in progress
13243      * @return {Boolean}
13244      */
13245     isUpdating : function(){
13246         if(this.transaction){
13247             return Roo.Ajax.isLoading(this.transaction);
13248         }
13249         return false;
13250     }
13251 });
13252
13253 /**
13254  * @class Roo.UpdateManager.defaults
13255  * @static (not really - but it helps the doc tool)
13256  * The defaults collection enables customizing the default properties of UpdateManager
13257  */
13258    Roo.UpdateManager.defaults = {
13259        /**
13260          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
13261          * @type Number
13262          */
13263          timeout : 30,
13264
13265          /**
13266          * True to process scripts by default (Defaults to false).
13267          * @type Boolean
13268          */
13269         loadScripts : false,
13270
13271         /**
13272         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
13273         * @type String
13274         */
13275         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
13276         /**
13277          * Whether to append unique parameter on get request to disable caching (Defaults to false).
13278          * @type Boolean
13279          */
13280         disableCaching : false,
13281         /**
13282          * Whether to show indicatorText when loading (Defaults to true).
13283          * @type Boolean
13284          */
13285         showLoadIndicator : true,
13286         /**
13287          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
13288          * @type String
13289          */
13290         indicatorText : '<div class="loading-indicator">Loading...</div>'
13291    };
13292
13293 /**
13294  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
13295  *Usage:
13296  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
13297  * @param {String/HTMLElement/Roo.Element} el The element to update
13298  * @param {String} url The url
13299  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
13300  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
13301  * @static
13302  * @deprecated
13303  * @member Roo.UpdateManager
13304  */
13305 Roo.UpdateManager.updateElement = function(el, url, params, options){
13306     var um = Roo.get(el, true).getUpdateManager();
13307     Roo.apply(um, options);
13308     um.update(url, params, options ? options.callback : null);
13309 };
13310 // alias for backwards compat
13311 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
13312 /**
13313  * @class Roo.UpdateManager.BasicRenderer
13314  * Default Content renderer. Updates the elements innerHTML with the responseText.
13315  */
13316 Roo.UpdateManager.BasicRenderer = function(){};
13317
13318 Roo.UpdateManager.BasicRenderer.prototype = {
13319     /**
13320      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
13321      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
13322      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
13323      * @param {Roo.Element} el The element being rendered
13324      * @param {Object} response The YUI Connect response object
13325      * @param {UpdateManager} updateManager The calling update manager
13326      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
13327      */
13328      render : function(el, response, updateManager, callback){
13329         el.update(response.responseText, updateManager.loadScripts, callback);
13330     }
13331 };
13332 /*
13333  * Based on:
13334  * Roo JS
13335  * (c)) Alan Knowles
13336  * Licence : LGPL
13337  */
13338
13339
13340 /**
13341  * @class Roo.DomTemplate
13342  * @extends Roo.Template
13343  * An effort at a dom based template engine..
13344  *
13345  * Similar to XTemplate, except it uses dom parsing to create the template..
13346  *
13347  * Supported features:
13348  *
13349  *  Tags:
13350
13351 <pre><code>
13352       {a_variable} - output encoded.
13353       {a_variable.format:("Y-m-d")} - call a method on the variable
13354       {a_variable:raw} - unencoded output
13355       {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
13356       {a_variable:this.method_on_template(...)} - call a method on the template object.
13357  
13358 </code></pre>
13359  *  The tpl tag:
13360 <pre><code>
13361         &lt;div roo-for="a_variable or condition.."&gt;&lt;/div&gt;
13362         &lt;div roo-if="a_variable or condition"&gt;&lt;/div&gt;
13363         &lt;div roo-exec="some javascript"&gt;&lt;/div&gt;
13364         &lt;div roo-name="named_template"&gt;&lt;/div&gt; 
13365   
13366 </code></pre>
13367  *      
13368  */
13369 Roo.DomTemplate = function()
13370 {
13371      Roo.DomTemplate.superclass.constructor.apply(this, arguments);
13372      if (this.html) {
13373         this.compile();
13374      }
13375 };
13376
13377
13378 Roo.extend(Roo.DomTemplate, Roo.Template, {
13379     /**
13380      * id counter for sub templates.
13381      */
13382     id : 0,
13383     /**
13384      * flag to indicate if dom parser is inside a pre,
13385      * it will strip whitespace if not.
13386      */
13387     inPre : false,
13388     
13389     /**
13390      * The various sub templates
13391      */
13392     tpls : false,
13393     
13394     
13395     
13396     /**
13397      *
13398      * basic tag replacing syntax
13399      * WORD:WORD()
13400      *
13401      * // you can fake an object call by doing this
13402      *  x.t:(test,tesT) 
13403      * 
13404      */
13405     re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
13406     //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
13407     
13408     iterChild : function (node, method) {
13409         
13410         var oldPre = this.inPre;
13411         if (node.tagName == 'PRE') {
13412             this.inPre = true;
13413         }
13414         for( var i = 0; i < node.childNodes.length; i++) {
13415             method.call(this, node.childNodes[i]);
13416         }
13417         this.inPre = oldPre;
13418     },
13419     
13420     
13421     
13422     /**
13423      * compile the template
13424      *
13425      * This is not recursive, so I'm not sure how nested templates are really going to be handled..
13426      *
13427      */
13428     compile: function()
13429     {
13430         var s = this.html;
13431         
13432         // covert the html into DOM...
13433         var doc = false;
13434         var div =false;
13435         try {
13436             doc = document.implementation.createHTMLDocument("");
13437             doc.documentElement.innerHTML =   this.html  ;
13438             div = doc.documentElement;
13439         } catch (e) {
13440             // old IE... - nasty -- it causes all sorts of issues.. with
13441             // images getting pulled from server..
13442             div = document.createElement('div');
13443             div.innerHTML = this.html;
13444         }
13445         //doc.documentElement.innerHTML = htmlBody
13446          
13447         
13448         
13449         this.tpls = [];
13450         var _t = this;
13451         this.iterChild(div, function(n) {_t.compileNode(n, true); });
13452         
13453         var tpls = this.tpls;
13454         
13455         // create a top level template from the snippet..
13456         
13457         //Roo.log(div.innerHTML);
13458         
13459         var tpl = {
13460             uid : 'master',
13461             id : this.id++,
13462             attr : false,
13463             value : false,
13464             body : div.innerHTML,
13465             
13466             forCall : false,
13467             execCall : false,
13468             dom : div,
13469             isTop : true
13470             
13471         };
13472         tpls.unshift(tpl);
13473         
13474         
13475         // compile them...
13476         this.tpls = [];
13477         Roo.each(tpls, function(tp){
13478             this.compileTpl(tp);
13479             this.tpls[tp.id] = tp;
13480         }, this);
13481         
13482         this.master = tpls[0];
13483         return this;
13484         
13485         
13486     },
13487     
13488     compileNode : function(node, istop) {
13489         // test for
13490         //Roo.log(node);
13491         
13492         
13493         // skip anything not a tag..
13494         if (node.nodeType != 1) {
13495             if (node.nodeType == 3 && !this.inPre) {
13496                 // reduce white space..
13497                 node.nodeValue = node.nodeValue.replace(/\s+/g, ' '); 
13498                 
13499             }
13500             return;
13501         }
13502         
13503         var tpl = {
13504             uid : false,
13505             id : false,
13506             attr : false,
13507             value : false,
13508             body : '',
13509             
13510             forCall : false,
13511             execCall : false,
13512             dom : false,
13513             isTop : istop
13514             
13515             
13516         };
13517         
13518         
13519         switch(true) {
13520             case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
13521             case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
13522             case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
13523             case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
13524             // no default..
13525         }
13526         
13527         
13528         if (!tpl.attr) {
13529             // just itterate children..
13530             this.iterChild(node,this.compileNode);
13531             return;
13532         }
13533         tpl.uid = this.id++;
13534         tpl.value = node.getAttribute('roo-' +  tpl.attr);
13535         node.removeAttribute('roo-'+ tpl.attr);
13536         if (tpl.attr != 'name') {
13537             var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
13538             node.parentNode.replaceChild(placeholder,  node);
13539         } else {
13540             
13541             var placeholder =  document.createElement('span');
13542             placeholder.className = 'roo-tpl-' + tpl.value;
13543             node.parentNode.replaceChild(placeholder,  node);
13544         }
13545         
13546         // parent now sees '{domtplXXXX}
13547         this.iterChild(node,this.compileNode);
13548         
13549         // we should now have node body...
13550         var div = document.createElement('div');
13551         div.appendChild(node);
13552         tpl.dom = node;
13553         // this has the unfortunate side effect of converting tagged attributes
13554         // eg. href="{...}" into %7C...%7D
13555         // this has been fixed by searching for those combo's although it's a bit hacky..
13556         
13557         
13558         tpl.body = div.innerHTML;
13559         
13560         
13561          
13562         tpl.id = tpl.uid;
13563         switch(tpl.attr) {
13564             case 'for' :
13565                 switch (tpl.value) {
13566                     case '.':  tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
13567                     case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
13568                     default:   tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
13569                 }
13570                 break;
13571             
13572             case 'exec':
13573                 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
13574                 break;
13575             
13576             case 'if':     
13577                 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
13578                 break;
13579             
13580             case 'name':
13581                 tpl.id  = tpl.value; // replace non characters???
13582                 break;
13583             
13584         }
13585         
13586         
13587         this.tpls.push(tpl);
13588         
13589         
13590         
13591     },
13592     
13593     
13594     
13595     
13596     /**
13597      * Compile a segment of the template into a 'sub-template'
13598      *
13599      * 
13600      * 
13601      *
13602      */
13603     compileTpl : function(tpl)
13604     {
13605         var fm = Roo.util.Format;
13606         var useF = this.disableFormats !== true;
13607         
13608         var sep = Roo.isGecko ? "+\n" : ",\n";
13609         
13610         var undef = function(str) {
13611             Roo.debug && Roo.log("Property not found :"  + str);
13612             return '';
13613         };
13614           
13615         //Roo.log(tpl.body);
13616         
13617         
13618         
13619         var fn = function(m, lbrace, name, format, args)
13620         {
13621             //Roo.log("ARGS");
13622             //Roo.log(arguments);
13623             args = args ? args.replace(/\\'/g,"'") : args;
13624             //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
13625             if (typeof(format) == 'undefined') {
13626                 format =  'htmlEncode'; 
13627             }
13628             if (format == 'raw' ) {
13629                 format = false;
13630             }
13631             
13632             if(name.substr(0, 6) == 'domtpl'){
13633                 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
13634             }
13635             
13636             // build an array of options to determine if value is undefined..
13637             
13638             // basically get 'xxxx.yyyy' then do
13639             // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
13640             //    (function () { Roo.log("Property not found"); return ''; })() :
13641             //    ......
13642             
13643             var udef_ar = [];
13644             var lookfor = '';
13645             Roo.each(name.split('.'), function(st) {
13646                 lookfor += (lookfor.length ? '.': '') + st;
13647                 udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
13648             });
13649             
13650             var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
13651             
13652             
13653             if(format && useF){
13654                 
13655                 args = args ? ',' + args : "";
13656                  
13657                 if(format.substr(0, 5) != "this."){
13658                     format = "fm." + format + '(';
13659                 }else{
13660                     format = 'this.call("'+ format.substr(5) + '", ';
13661                     args = ", values";
13662                 }
13663                 
13664                 return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
13665             }
13666              
13667             if (args && args.length) {
13668                 // called with xxyx.yuu:(test,test)
13669                 // change to ()
13670                 return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
13671             }
13672             // raw.. - :raw modifier..
13673             return "'"+ sep + udef_st  + name + ")"+sep+"'";
13674             
13675         };
13676         var body;
13677         // branched to use + in gecko and [].join() in others
13678         if(Roo.isGecko){
13679             body = "tpl.compiled = function(values, parent){  with(values) { return '" +
13680                    tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
13681                     "';};};";
13682         }else{
13683             body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
13684             body.push(tpl.body.replace(/(\r\n|\n)/g,
13685                             '\\n').replace(/'/g, "\\'").replace(this.re, fn));
13686             body.push("'].join('');};};");
13687             body = body.join('');
13688         }
13689         
13690         Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
13691        
13692         /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
13693         eval(body);
13694         
13695         return this;
13696     },
13697      
13698     /**
13699      * same as applyTemplate, except it's done to one of the subTemplates
13700      * when using named templates, you can do:
13701      *
13702      * var str = pl.applySubTemplate('your-name', values);
13703      *
13704      * 
13705      * @param {Number} id of the template
13706      * @param {Object} values to apply to template
13707      * @param {Object} parent (normaly the instance of this object)
13708      */
13709     applySubTemplate : function(id, values, parent)
13710     {
13711         
13712         
13713         var t = this.tpls[id];
13714         
13715         
13716         try { 
13717             if(t.ifCall && !t.ifCall.call(this, values, parent)){
13718                 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
13719                 return '';
13720             }
13721         } catch(e) {
13722             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
13723             Roo.log(values);
13724           
13725             return '';
13726         }
13727         try { 
13728             
13729             if(t.execCall && t.execCall.call(this, values, parent)){
13730                 return '';
13731             }
13732         } catch(e) {
13733             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
13734             Roo.log(values);
13735             return '';
13736         }
13737         
13738         try {
13739             var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
13740             parent = t.target ? values : parent;
13741             if(t.forCall && vs instanceof Array){
13742                 var buf = [];
13743                 for(var i = 0, len = vs.length; i < len; i++){
13744                     try {
13745                         buf[buf.length] = t.compiled.call(this, vs[i], parent);
13746                     } catch (e) {
13747                         Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
13748                         Roo.log(e.body);
13749                         //Roo.log(t.compiled);
13750                         Roo.log(vs[i]);
13751                     }   
13752                 }
13753                 return buf.join('');
13754             }
13755         } catch (e) {
13756             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
13757             Roo.log(values);
13758             return '';
13759         }
13760         try {
13761             return t.compiled.call(this, vs, parent);
13762         } catch (e) {
13763             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
13764             Roo.log(e.body);
13765             //Roo.log(t.compiled);
13766             Roo.log(values);
13767             return '';
13768         }
13769     },
13770
13771    
13772
13773     applyTemplate : function(values){
13774         return this.master.compiled.call(this, values, {});
13775         //var s = this.subs;
13776     },
13777
13778     apply : function(){
13779         return this.applyTemplate.apply(this, arguments);
13780     }
13781
13782  });
13783
13784 Roo.DomTemplate.from = function(el){
13785     el = Roo.getDom(el);
13786     return new Roo.Domtemplate(el.value || el.innerHTML);
13787 };/*
13788  * Based on:
13789  * Ext JS Library 1.1.1
13790  * Copyright(c) 2006-2007, Ext JS, LLC.
13791  *
13792  * Originally Released Under LGPL - original licence link has changed is not relivant.
13793  *
13794  * Fork - LGPL
13795  * <script type="text/javascript">
13796  */
13797
13798 /**
13799  * @class Roo.util.DelayedTask
13800  * Provides a convenient method of performing setTimeout where a new
13801  * timeout cancels the old timeout. An example would be performing validation on a keypress.
13802  * You can use this class to buffer
13803  * the keypress events for a certain number of milliseconds, and perform only if they stop
13804  * for that amount of time.
13805  * @constructor The parameters to this constructor serve as defaults and are not required.
13806  * @param {Function} fn (optional) The default function to timeout
13807  * @param {Object} scope (optional) The default scope of that timeout
13808  * @param {Array} args (optional) The default Array of arguments
13809  */
13810 Roo.util.DelayedTask = function(fn, scope, args){
13811     var id = null, d, t;
13812
13813     var call = function(){
13814         var now = new Date().getTime();
13815         if(now - t >= d){
13816             clearInterval(id);
13817             id = null;
13818             fn.apply(scope, args || []);
13819         }
13820     };
13821     /**
13822      * Cancels any pending timeout and queues a new one
13823      * @param {Number} delay The milliseconds to delay
13824      * @param {Function} newFn (optional) Overrides function passed to constructor
13825      * @param {Object} newScope (optional) Overrides scope passed to constructor
13826      * @param {Array} newArgs (optional) Overrides args passed to constructor
13827      */
13828     this.delay = function(delay, newFn, newScope, newArgs){
13829         if(id && delay != d){
13830             this.cancel();
13831         }
13832         d = delay;
13833         t = new Date().getTime();
13834         fn = newFn || fn;
13835         scope = newScope || scope;
13836         args = newArgs || args;
13837         if(!id){
13838             id = setInterval(call, d);
13839         }
13840     };
13841
13842     /**
13843      * Cancel the last queued timeout
13844      */
13845     this.cancel = function(){
13846         if(id){
13847             clearInterval(id);
13848             id = null;
13849         }
13850     };
13851 };/*
13852  * Based on:
13853  * Ext JS Library 1.1.1
13854  * Copyright(c) 2006-2007, Ext JS, LLC.
13855  *
13856  * Originally Released Under LGPL - original licence link has changed is not relivant.
13857  *
13858  * Fork - LGPL
13859  * <script type="text/javascript">
13860  */
13861 /**
13862  * @class Roo.util.TaskRunner
13863  * Manage background tasks - not sure why this is better that setInterval?
13864  * @static
13865  *
13866  */
13867  
13868 Roo.util.TaskRunner = function(interval){
13869     interval = interval || 10;
13870     var tasks = [], removeQueue = [];
13871     var id = 0;
13872     var running = false;
13873
13874     var stopThread = function(){
13875         running = false;
13876         clearInterval(id);
13877         id = 0;
13878     };
13879
13880     var startThread = function(){
13881         if(!running){
13882             running = true;
13883             id = setInterval(runTasks, interval);
13884         }
13885     };
13886
13887     var removeTask = function(task){
13888         removeQueue.push(task);
13889         if(task.onStop){
13890             task.onStop();
13891         }
13892     };
13893
13894     var runTasks = function(){
13895         if(removeQueue.length > 0){
13896             for(var i = 0, len = removeQueue.length; i < len; i++){
13897                 tasks.remove(removeQueue[i]);
13898             }
13899             removeQueue = [];
13900             if(tasks.length < 1){
13901                 stopThread();
13902                 return;
13903             }
13904         }
13905         var now = new Date().getTime();
13906         for(var i = 0, len = tasks.length; i < len; ++i){
13907             var t = tasks[i];
13908             var itime = now - t.taskRunTime;
13909             if(t.interval <= itime){
13910                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
13911                 t.taskRunTime = now;
13912                 if(rt === false || t.taskRunCount === t.repeat){
13913                     removeTask(t);
13914                     return;
13915                 }
13916             }
13917             if(t.duration && t.duration <= (now - t.taskStartTime)){
13918                 removeTask(t);
13919             }
13920         }
13921     };
13922
13923     /**
13924      * Queues a new task.
13925      * @param {Object} task
13926      *
13927      * Task property : interval = how frequent to run.
13928      * Task object should implement
13929      * function run()
13930      * Task object may implement
13931      * function onStop()
13932      */
13933     this.start = function(task){
13934         tasks.push(task);
13935         task.taskStartTime = new Date().getTime();
13936         task.taskRunTime = 0;
13937         task.taskRunCount = 0;
13938         startThread();
13939         return task;
13940     };
13941     /**
13942      * Stop  new task.
13943      * @param {Object} task
13944      */
13945     this.stop = function(task){
13946         removeTask(task);
13947         return task;
13948     };
13949     /**
13950      * Stop all Tasks
13951      */
13952     this.stopAll = function(){
13953         stopThread();
13954         for(var i = 0, len = tasks.length; i < len; i++){
13955             if(tasks[i].onStop){
13956                 tasks[i].onStop();
13957             }
13958         }
13959         tasks = [];
13960         removeQueue = [];
13961     };
13962 };
13963
13964 Roo.TaskMgr = new Roo.util.TaskRunner();/*
13965  * Based on:
13966  * Ext JS Library 1.1.1
13967  * Copyright(c) 2006-2007, Ext JS, LLC.
13968  *
13969  * Originally Released Under LGPL - original licence link has changed is not relivant.
13970  *
13971  * Fork - LGPL
13972  * <script type="text/javascript">
13973  */
13974
13975  
13976 /**
13977  * @class Roo.util.MixedCollection
13978  * @extends Roo.util.Observable
13979  * A Collection class that maintains both numeric indexes and keys and exposes events.
13980  * @constructor
13981  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
13982  * collection (defaults to false)
13983  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
13984  * and return the key value for that item.  This is used when available to look up the key on items that
13985  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
13986  * equivalent to providing an implementation for the {@link #getKey} method.
13987  */
13988 Roo.util.MixedCollection = function(allowFunctions, keyFn){
13989     this.items = [];
13990     this.map = {};
13991     this.keys = [];
13992     this.length = 0;
13993     this.addEvents({
13994         /**
13995          * @event clear
13996          * Fires when the collection is cleared.
13997          */
13998         "clear" : true,
13999         /**
14000          * @event add
14001          * Fires when an item is added to the collection.
14002          * @param {Number} index The index at which the item was added.
14003          * @param {Object} o The item added.
14004          * @param {String} key The key associated with the added item.
14005          */
14006         "add" : true,
14007         /**
14008          * @event replace
14009          * Fires when an item is replaced in the collection.
14010          * @param {String} key he key associated with the new added.
14011          * @param {Object} old The item being replaced.
14012          * @param {Object} new The new item.
14013          */
14014         "replace" : true,
14015         /**
14016          * @event remove
14017          * Fires when an item is removed from the collection.
14018          * @param {Object} o The item being removed.
14019          * @param {String} key (optional) The key associated with the removed item.
14020          */
14021         "remove" : true,
14022         "sort" : true
14023     });
14024     this.allowFunctions = allowFunctions === true;
14025     if(keyFn){
14026         this.getKey = keyFn;
14027     }
14028     Roo.util.MixedCollection.superclass.constructor.call(this);
14029 };
14030
14031 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
14032     allowFunctions : false,
14033     
14034 /**
14035  * Adds an item to the collection.
14036  * @param {String} key The key to associate with the item
14037  * @param {Object} o The item to add.
14038  * @return {Object} The item added.
14039  */
14040     add : function(key, o){
14041         if(arguments.length == 1){
14042             o = arguments[0];
14043             key = this.getKey(o);
14044         }
14045         if(typeof key == "undefined" || key === null){
14046             this.length++;
14047             this.items.push(o);
14048             this.keys.push(null);
14049         }else{
14050             var old = this.map[key];
14051             if(old){
14052                 return this.replace(key, o);
14053             }
14054             this.length++;
14055             this.items.push(o);
14056             this.map[key] = o;
14057             this.keys.push(key);
14058         }
14059         this.fireEvent("add", this.length-1, o, key);
14060         return o;
14061     },
14062        
14063 /**
14064   * MixedCollection has a generic way to fetch keys if you implement getKey.
14065 <pre><code>
14066 // normal way
14067 var mc = new Roo.util.MixedCollection();
14068 mc.add(someEl.dom.id, someEl);
14069 mc.add(otherEl.dom.id, otherEl);
14070 //and so on
14071
14072 // using getKey
14073 var mc = new Roo.util.MixedCollection();
14074 mc.getKey = function(el){
14075    return el.dom.id;
14076 };
14077 mc.add(someEl);
14078 mc.add(otherEl);
14079
14080 // or via the constructor
14081 var mc = new Roo.util.MixedCollection(false, function(el){
14082    return el.dom.id;
14083 });
14084 mc.add(someEl);
14085 mc.add(otherEl);
14086 </code></pre>
14087  * @param o {Object} The item for which to find the key.
14088  * @return {Object} The key for the passed item.
14089  */
14090     getKey : function(o){
14091          return o.id; 
14092     },
14093    
14094 /**
14095  * Replaces an item in the collection.
14096  * @param {String} key The key associated with the item to replace, or the item to replace.
14097  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
14098  * @return {Object}  The new item.
14099  */
14100     replace : function(key, o){
14101         if(arguments.length == 1){
14102             o = arguments[0];
14103             key = this.getKey(o);
14104         }
14105         var old = this.item(key);
14106         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
14107              return this.add(key, o);
14108         }
14109         var index = this.indexOfKey(key);
14110         this.items[index] = o;
14111         this.map[key] = o;
14112         this.fireEvent("replace", key, old, o);
14113         return o;
14114     },
14115    
14116 /**
14117  * Adds all elements of an Array or an Object to the collection.
14118  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
14119  * an Array of values, each of which are added to the collection.
14120  */
14121     addAll : function(objs){
14122         if(arguments.length > 1 || objs instanceof Array){
14123             var args = arguments.length > 1 ? arguments : objs;
14124             for(var i = 0, len = args.length; i < len; i++){
14125                 this.add(args[i]);
14126             }
14127         }else{
14128             for(var key in objs){
14129                 if(this.allowFunctions || typeof objs[key] != "function"){
14130                     this.add(key, objs[key]);
14131                 }
14132             }
14133         }
14134     },
14135    
14136 /**
14137  * Executes the specified function once for every item in the collection, passing each
14138  * item as the first and only parameter. returning false from the function will stop the iteration.
14139  * @param {Function} fn The function to execute for each item.
14140  * @param {Object} scope (optional) The scope in which to execute the function.
14141  */
14142     each : function(fn, scope){
14143         var items = [].concat(this.items); // each safe for removal
14144         for(var i = 0, len = items.length; i < len; i++){
14145             if(fn.call(scope || items[i], items[i], i, len) === false){
14146                 break;
14147             }
14148         }
14149     },
14150    
14151 /**
14152  * Executes the specified function once for every key in the collection, passing each
14153  * key, and its associated item as the first two parameters.
14154  * @param {Function} fn The function to execute for each item.
14155  * @param {Object} scope (optional) The scope in which to execute the function.
14156  */
14157     eachKey : function(fn, scope){
14158         for(var i = 0, len = this.keys.length; i < len; i++){
14159             fn.call(scope || window, this.keys[i], this.items[i], i, len);
14160         }
14161     },
14162    
14163 /**
14164  * Returns the first item in the collection which elicits a true return value from the
14165  * passed selection function.
14166  * @param {Function} fn The selection function to execute for each item.
14167  * @param {Object} scope (optional) The scope in which to execute the function.
14168  * @return {Object} The first item in the collection which returned true from the selection function.
14169  */
14170     find : function(fn, scope){
14171         for(var i = 0, len = this.items.length; i < len; i++){
14172             if(fn.call(scope || window, this.items[i], this.keys[i])){
14173                 return this.items[i];
14174             }
14175         }
14176         return null;
14177     },
14178    
14179 /**
14180  * Inserts an item at the specified index in the collection.
14181  * @param {Number} index The index to insert the item at.
14182  * @param {String} key The key to associate with the new item, or the item itself.
14183  * @param {Object} o  (optional) If the second parameter was a key, the new item.
14184  * @return {Object} The item inserted.
14185  */
14186     insert : function(index, key, o){
14187         if(arguments.length == 2){
14188             o = arguments[1];
14189             key = this.getKey(o);
14190         }
14191         if(index >= this.length){
14192             return this.add(key, o);
14193         }
14194         this.length++;
14195         this.items.splice(index, 0, o);
14196         if(typeof key != "undefined" && key != null){
14197             this.map[key] = o;
14198         }
14199         this.keys.splice(index, 0, key);
14200         this.fireEvent("add", index, o, key);
14201         return o;
14202     },
14203    
14204 /**
14205  * Removed an item from the collection.
14206  * @param {Object} o The item to remove.
14207  * @return {Object} The item removed.
14208  */
14209     remove : function(o){
14210         return this.removeAt(this.indexOf(o));
14211     },
14212    
14213 /**
14214  * Remove an item from a specified index in the collection.
14215  * @param {Number} index The index within the collection of the item to remove.
14216  */
14217     removeAt : function(index){
14218         if(index < this.length && index >= 0){
14219             this.length--;
14220             var o = this.items[index];
14221             this.items.splice(index, 1);
14222             var key = this.keys[index];
14223             if(typeof key != "undefined"){
14224                 delete this.map[key];
14225             }
14226             this.keys.splice(index, 1);
14227             this.fireEvent("remove", o, key);
14228         }
14229     },
14230    
14231 /**
14232  * Removed an item associated with the passed key fom the collection.
14233  * @param {String} key The key of the item to remove.
14234  */
14235     removeKey : function(key){
14236         return this.removeAt(this.indexOfKey(key));
14237     },
14238    
14239 /**
14240  * Returns the number of items in the collection.
14241  * @return {Number} the number of items in the collection.
14242  */
14243     getCount : function(){
14244         return this.length; 
14245     },
14246    
14247 /**
14248  * Returns index within the collection of the passed Object.
14249  * @param {Object} o The item to find the index of.
14250  * @return {Number} index of the item.
14251  */
14252     indexOf : function(o){
14253         if(!this.items.indexOf){
14254             for(var i = 0, len = this.items.length; i < len; i++){
14255                 if(this.items[i] == o) {
14256                     return i;
14257                 }
14258             }
14259             return -1;
14260         }else{
14261             return this.items.indexOf(o);
14262         }
14263     },
14264    
14265 /**
14266  * Returns index within the collection of the passed key.
14267  * @param {String} key The key to find the index of.
14268  * @return {Number} index of the key.
14269  */
14270     indexOfKey : function(key){
14271         if(!this.keys.indexOf){
14272             for(var i = 0, len = this.keys.length; i < len; i++){
14273                 if(this.keys[i] == key) {
14274                     return i;
14275                 }
14276             }
14277             return -1;
14278         }else{
14279             return this.keys.indexOf(key);
14280         }
14281     },
14282    
14283 /**
14284  * Returns the item associated with the passed key OR index. Key has priority over index.
14285  * @param {String/Number} key The key or index of the item.
14286  * @return {Object} The item associated with the passed key.
14287  */
14288     item : function(key){
14289         if (key === 'length') {
14290             return null;
14291         }
14292         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
14293         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
14294     },
14295     
14296 /**
14297  * Returns the item at the specified index.
14298  * @param {Number} index The index of the item.
14299  * @return {Object}
14300  */
14301     itemAt : function(index){
14302         return this.items[index];
14303     },
14304     
14305 /**
14306  * Returns the item associated with the passed key.
14307  * @param {String/Number} key The key of the item.
14308  * @return {Object} The item associated with the passed key.
14309  */
14310     key : function(key){
14311         return this.map[key];
14312     },
14313    
14314 /**
14315  * Returns true if the collection contains the passed Object as an item.
14316  * @param {Object} o  The Object to look for in the collection.
14317  * @return {Boolean} True if the collection contains the Object as an item.
14318  */
14319     contains : function(o){
14320         return this.indexOf(o) != -1;
14321     },
14322    
14323 /**
14324  * Returns true if the collection contains the passed Object as a key.
14325  * @param {String} key The key to look for in the collection.
14326  * @return {Boolean} True if the collection contains the Object as a key.
14327  */
14328     containsKey : function(key){
14329         return typeof this.map[key] != "undefined";
14330     },
14331    
14332 /**
14333  * Removes all items from the collection.
14334  */
14335     clear : function(){
14336         this.length = 0;
14337         this.items = [];
14338         this.keys = [];
14339         this.map = {};
14340         this.fireEvent("clear");
14341     },
14342    
14343 /**
14344  * Returns the first item in the collection.
14345  * @return {Object} the first item in the collection..
14346  */
14347     first : function(){
14348         return this.items[0]; 
14349     },
14350    
14351 /**
14352  * Returns the last item in the collection.
14353  * @return {Object} the last item in the collection..
14354  */
14355     last : function(){
14356         return this.items[this.length-1];   
14357     },
14358     
14359     _sort : function(property, dir, fn){
14360         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
14361         fn = fn || function(a, b){
14362             return a-b;
14363         };
14364         var c = [], k = this.keys, items = this.items;
14365         for(var i = 0, len = items.length; i < len; i++){
14366             c[c.length] = {key: k[i], value: items[i], index: i};
14367         }
14368         c.sort(function(a, b){
14369             var v = fn(a[property], b[property]) * dsc;
14370             if(v == 0){
14371                 v = (a.index < b.index ? -1 : 1);
14372             }
14373             return v;
14374         });
14375         for(var i = 0, len = c.length; i < len; i++){
14376             items[i] = c[i].value;
14377             k[i] = c[i].key;
14378         }
14379         this.fireEvent("sort", this);
14380     },
14381     
14382     /**
14383      * Sorts this collection with the passed comparison function
14384      * @param {String} direction (optional) "ASC" or "DESC"
14385      * @param {Function} fn (optional) comparison function
14386      */
14387     sort : function(dir, fn){
14388         this._sort("value", dir, fn);
14389     },
14390     
14391     /**
14392      * Sorts this collection by keys
14393      * @param {String} direction (optional) "ASC" or "DESC"
14394      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
14395      */
14396     keySort : function(dir, fn){
14397         this._sort("key", dir, fn || function(a, b){
14398             return String(a).toUpperCase()-String(b).toUpperCase();
14399         });
14400     },
14401     
14402     /**
14403      * Returns a range of items in this collection
14404      * @param {Number} startIndex (optional) defaults to 0
14405      * @param {Number} endIndex (optional) default to the last item
14406      * @return {Array} An array of items
14407      */
14408     getRange : function(start, end){
14409         var items = this.items;
14410         if(items.length < 1){
14411             return [];
14412         }
14413         start = start || 0;
14414         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
14415         var r = [];
14416         if(start <= end){
14417             for(var i = start; i <= end; i++) {
14418                     r[r.length] = items[i];
14419             }
14420         }else{
14421             for(var i = start; i >= end; i--) {
14422                     r[r.length] = items[i];
14423             }
14424         }
14425         return r;
14426     },
14427         
14428     /**
14429      * Filter the <i>objects</i> in this collection by a specific property. 
14430      * Returns a new collection that has been filtered.
14431      * @param {String} property A property on your objects
14432      * @param {String/RegExp} value Either string that the property values 
14433      * should start with or a RegExp to test against the property
14434      * @return {MixedCollection} The new filtered collection
14435      */
14436     filter : function(property, value){
14437         if(!value.exec){ // not a regex
14438             value = String(value);
14439             if(value.length == 0){
14440                 return this.clone();
14441             }
14442             value = new RegExp("^" + Roo.escapeRe(value), "i");
14443         }
14444         return this.filterBy(function(o){
14445             return o && value.test(o[property]);
14446         });
14447         },
14448     
14449     /**
14450      * Filter by a function. * Returns a new collection that has been filtered.
14451      * The passed function will be called with each 
14452      * object in the collection. If the function returns true, the value is included 
14453      * otherwise it is filtered.
14454      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
14455      * @param {Object} scope (optional) The scope of the function (defaults to this) 
14456      * @return {MixedCollection} The new filtered collection
14457      */
14458     filterBy : function(fn, scope){
14459         var r = new Roo.util.MixedCollection();
14460         r.getKey = this.getKey;
14461         var k = this.keys, it = this.items;
14462         for(var i = 0, len = it.length; i < len; i++){
14463             if(fn.call(scope||this, it[i], k[i])){
14464                                 r.add(k[i], it[i]);
14465                         }
14466         }
14467         return r;
14468     },
14469     
14470     /**
14471      * Creates a duplicate of this collection
14472      * @return {MixedCollection}
14473      */
14474     clone : function(){
14475         var r = new Roo.util.MixedCollection();
14476         var k = this.keys, it = this.items;
14477         for(var i = 0, len = it.length; i < len; i++){
14478             r.add(k[i], it[i]);
14479         }
14480         r.getKey = this.getKey;
14481         return r;
14482     }
14483 });
14484 /**
14485  * Returns the item associated with the passed key or index.
14486  * @method
14487  * @param {String/Number} key The key or index of the item.
14488  * @return {Object} The item associated with the passed key.
14489  */
14490 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
14491  * Based on:
14492  * Ext JS Library 1.1.1
14493  * Copyright(c) 2006-2007, Ext JS, LLC.
14494  *
14495  * Originally Released Under LGPL - original licence link has changed is not relivant.
14496  *
14497  * Fork - LGPL
14498  * <script type="text/javascript">
14499  */
14500 /**
14501  * @class Roo.util.JSON
14502  * Modified version of Douglas Crockford"s json.js that doesn"t
14503  * mess with the Object prototype 
14504  * http://www.json.org/js.html
14505  * @static
14506  */
14507 Roo.util.JSON = new (function(){
14508     var useHasOwn = {}.hasOwnProperty ? true : false;
14509     
14510     // crashes Safari in some instances
14511     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
14512     
14513     var pad = function(n) {
14514         return n < 10 ? "0" + n : n;
14515     };
14516     
14517     var m = {
14518         "\b": '\\b',
14519         "\t": '\\t',
14520         "\n": '\\n',
14521         "\f": '\\f',
14522         "\r": '\\r',
14523         '"' : '\\"',
14524         "\\": '\\\\'
14525     };
14526
14527     var encodeString = function(s){
14528         if (/["\\\x00-\x1f]/.test(s)) {
14529             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
14530                 var c = m[b];
14531                 if(c){
14532                     return c;
14533                 }
14534                 c = b.charCodeAt();
14535                 return "\\u00" +
14536                     Math.floor(c / 16).toString(16) +
14537                     (c % 16).toString(16);
14538             }) + '"';
14539         }
14540         return '"' + s + '"';
14541     };
14542     
14543     var encodeArray = function(o){
14544         var a = ["["], b, i, l = o.length, v;
14545             for (i = 0; i < l; i += 1) {
14546                 v = o[i];
14547                 switch (typeof v) {
14548                     case "undefined":
14549                     case "function":
14550                     case "unknown":
14551                         break;
14552                     default:
14553                         if (b) {
14554                             a.push(',');
14555                         }
14556                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
14557                         b = true;
14558                 }
14559             }
14560             a.push("]");
14561             return a.join("");
14562     };
14563     
14564     var encodeDate = function(o){
14565         return '"' + o.getFullYear() + "-" +
14566                 pad(o.getMonth() + 1) + "-" +
14567                 pad(o.getDate()) + "T" +
14568                 pad(o.getHours()) + ":" +
14569                 pad(o.getMinutes()) + ":" +
14570                 pad(o.getSeconds()) + '"';
14571     };
14572     
14573     /**
14574      * Encodes an Object, Array or other value
14575      * @param {Mixed} o The variable to encode
14576      * @return {String} The JSON string
14577      */
14578     this.encode = function(o)
14579     {
14580         // should this be extended to fully wrap stringify..
14581         
14582         if(typeof o == "undefined" || o === null){
14583             return "null";
14584         }else if(o instanceof Array){
14585             return encodeArray(o);
14586         }else if(o instanceof Date){
14587             return encodeDate(o);
14588         }else if(typeof o == "string"){
14589             return encodeString(o);
14590         }else if(typeof o == "number"){
14591             return isFinite(o) ? String(o) : "null";
14592         }else if(typeof o == "boolean"){
14593             return String(o);
14594         }else {
14595             var a = ["{"], b, i, v;
14596             for (i in o) {
14597                 if(!useHasOwn || o.hasOwnProperty(i)) {
14598                     v = o[i];
14599                     switch (typeof v) {
14600                     case "undefined":
14601                     case "function":
14602                     case "unknown":
14603                         break;
14604                     default:
14605                         if(b){
14606                             a.push(',');
14607                         }
14608                         a.push(this.encode(i), ":",
14609                                 v === null ? "null" : this.encode(v));
14610                         b = true;
14611                     }
14612                 }
14613             }
14614             a.push("}");
14615             return a.join("");
14616         }
14617     };
14618     
14619     /**
14620      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
14621      * @param {String} json The JSON string
14622      * @return {Object} The resulting object
14623      */
14624     this.decode = function(json){
14625         
14626         return  /** eval:var:json */ eval("(" + json + ')');
14627     };
14628 })();
14629 /** 
14630  * Shorthand for {@link Roo.util.JSON#encode}
14631  * @member Roo encode 
14632  * @method */
14633 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
14634 /** 
14635  * Shorthand for {@link Roo.util.JSON#decode}
14636  * @member Roo decode 
14637  * @method */
14638 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
14639 /*
14640  * Based on:
14641  * Ext JS Library 1.1.1
14642  * Copyright(c) 2006-2007, Ext JS, LLC.
14643  *
14644  * Originally Released Under LGPL - original licence link has changed is not relivant.
14645  *
14646  * Fork - LGPL
14647  * <script type="text/javascript">
14648  */
14649  
14650 /**
14651  * @class Roo.util.Format
14652  * Reusable data formatting functions
14653  * @static
14654  */
14655 Roo.util.Format = function(){
14656     var trimRe = /^\s+|\s+$/g;
14657     return {
14658         /**
14659          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
14660          * @param {String} value The string to truncate
14661          * @param {Number} length The maximum length to allow before truncating
14662          * @return {String} The converted text
14663          */
14664         ellipsis : function(value, len){
14665             if(value && value.length > len){
14666                 return value.substr(0, len-3)+"...";
14667             }
14668             return value;
14669         },
14670
14671         /**
14672          * Checks a reference and converts it to empty string if it is undefined
14673          * @param {Mixed} value Reference to check
14674          * @return {Mixed} Empty string if converted, otherwise the original value
14675          */
14676         undef : function(value){
14677             return typeof value != "undefined" ? value : "";
14678         },
14679
14680         /**
14681          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
14682          * @param {String} value The string to encode
14683          * @return {String} The encoded text
14684          */
14685         htmlEncode : function(value){
14686             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
14687         },
14688
14689         /**
14690          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
14691          * @param {String} value The string to decode
14692          * @return {String} The decoded text
14693          */
14694         htmlDecode : function(value){
14695             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
14696         },
14697
14698         /**
14699          * Trims any whitespace from either side of a string
14700          * @param {String} value The text to trim
14701          * @return {String} The trimmed text
14702          */
14703         trim : function(value){
14704             return String(value).replace(trimRe, "");
14705         },
14706
14707         /**
14708          * Returns a substring from within an original string
14709          * @param {String} value The original text
14710          * @param {Number} start The start index of the substring
14711          * @param {Number} length The length of the substring
14712          * @return {String} The substring
14713          */
14714         substr : function(value, start, length){
14715             return String(value).substr(start, length);
14716         },
14717
14718         /**
14719          * Converts a string to all lower case letters
14720          * @param {String} value The text to convert
14721          * @return {String} The converted text
14722          */
14723         lowercase : function(value){
14724             return String(value).toLowerCase();
14725         },
14726
14727         /**
14728          * Converts a string to all upper case letters
14729          * @param {String} value The text to convert
14730          * @return {String} The converted text
14731          */
14732         uppercase : function(value){
14733             return String(value).toUpperCase();
14734         },
14735
14736         /**
14737          * Converts the first character only of a string to upper case
14738          * @param {String} value The text to convert
14739          * @return {String} The converted text
14740          */
14741         capitalize : function(value){
14742             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
14743         },
14744
14745         // private
14746         call : function(value, fn){
14747             if(arguments.length > 2){
14748                 var args = Array.prototype.slice.call(arguments, 2);
14749                 args.unshift(value);
14750                  
14751                 return /** eval:var:value */  eval(fn).apply(window, args);
14752             }else{
14753                 /** eval:var:value */
14754                 return /** eval:var:value */ eval(fn).call(window, value);
14755             }
14756         },
14757
14758        
14759         /**
14760          * safer version of Math.toFixed..??/
14761          * @param {Number/String} value The numeric value to format
14762          * @param {Number/String} value Decimal places 
14763          * @return {String} The formatted currency string
14764          */
14765         toFixed : function(v, n)
14766         {
14767             // why not use to fixed - precision is buggered???
14768             if (!n) {
14769                 return Math.round(v-0);
14770             }
14771             var fact = Math.pow(10,n+1);
14772             v = (Math.round((v-0)*fact))/fact;
14773             var z = (''+fact).substring(2);
14774             if (v == Math.floor(v)) {
14775                 return Math.floor(v) + '.' + z;
14776             }
14777             
14778             // now just padd decimals..
14779             var ps = String(v).split('.');
14780             var fd = (ps[1] + z);
14781             var r = fd.substring(0,n); 
14782             var rm = fd.substring(n); 
14783             if (rm < 5) {
14784                 return ps[0] + '.' + r;
14785             }
14786             r*=1; // turn it into a number;
14787             r++;
14788             if (String(r).length != n) {
14789                 ps[0]*=1;
14790                 ps[0]++;
14791                 r = String(r).substring(1); // chop the end off.
14792             }
14793             
14794             return ps[0] + '.' + r;
14795              
14796         },
14797         
14798         /**
14799          * Format a number as US currency
14800          * @param {Number/String} value The numeric value to format
14801          * @return {String} The formatted currency string
14802          */
14803         usMoney : function(v){
14804             return '$' + Roo.util.Format.number(v);
14805         },
14806         
14807         /**
14808          * Format a number
14809          * eventually this should probably emulate php's number_format
14810          * @param {Number/String} value The numeric value to format
14811          * @param {Number} decimals number of decimal places
14812          * @param {String} delimiter for thousands (default comma)
14813          * @return {String} The formatted currency string
14814          */
14815         number : function(v, decimals, thousandsDelimiter)
14816         {
14817             // multiply and round.
14818             decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
14819             thousandsDelimiter = typeof(thousandsDelimiter) == 'undefined' ? ',' : thousandsDelimiter;
14820             
14821             var mul = Math.pow(10, decimals);
14822             var zero = String(mul).substring(1);
14823             v = (Math.round((v-0)*mul))/mul;
14824             
14825             // if it's '0' number.. then
14826             
14827             //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
14828             v = String(v);
14829             var ps = v.split('.');
14830             var whole = ps[0];
14831             
14832             var r = /(\d+)(\d{3})/;
14833             // add comma's
14834             
14835             if(thousandsDelimiter.length != 0) {
14836                 whole = whole.replace(/\B(?=(\d{3})+(?!\d))/g, thousandsDelimiter );
14837             } 
14838             
14839             var sub = ps[1] ?
14840                     // has decimals..
14841                     (decimals ?  ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
14842                     // does not have decimals
14843                     (decimals ? ('.' + zero) : '');
14844             
14845             
14846             return whole + sub ;
14847         },
14848         
14849         /**
14850          * Parse a value into a formatted date using the specified format pattern.
14851          * @param {Mixed} value The value to format
14852          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
14853          * @return {String} The formatted date string
14854          */
14855         date : function(v, format){
14856             if(!v){
14857                 return "";
14858             }
14859             if(!(v instanceof Date)){
14860                 v = new Date(Date.parse(v));
14861             }
14862             return v.dateFormat(format || Roo.util.Format.defaults.date);
14863         },
14864
14865         /**
14866          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
14867          * @param {String} format Any valid date format string
14868          * @return {Function} The date formatting function
14869          */
14870         dateRenderer : function(format){
14871             return function(v){
14872                 return Roo.util.Format.date(v, format);  
14873             };
14874         },
14875
14876         // private
14877         stripTagsRE : /<\/?[^>]+>/gi,
14878         
14879         /**
14880          * Strips all HTML tags
14881          * @param {Mixed} value The text from which to strip tags
14882          * @return {String} The stripped text
14883          */
14884         stripTags : function(v){
14885             return !v ? v : String(v).replace(this.stripTagsRE, "");
14886         },
14887         
14888         /**
14889          * Size in Mb,Gb etc.
14890          * @param {Number} value The number to be formated
14891          * @param {number} decimals how many decimal places
14892          * @return {String} the formated string
14893          */
14894         size : function(value, decimals)
14895         {
14896             var sizes = ['b', 'k', 'M', 'G', 'T'];
14897             if (value == 0) {
14898                 return 0;
14899             }
14900             var i = parseInt(Math.floor(Math.log(value) / Math.log(1024)));
14901             return Roo.util.Format.number(value/ Math.pow(1024, i) ,decimals)   + sizes[i];
14902         }
14903         
14904         
14905         
14906     };
14907 }();
14908 Roo.util.Format.defaults = {
14909     date : 'd/M/Y'
14910 };/*
14911  * Based on:
14912  * Ext JS Library 1.1.1
14913  * Copyright(c) 2006-2007, Ext JS, LLC.
14914  *
14915  * Originally Released Under LGPL - original licence link has changed is not relivant.
14916  *
14917  * Fork - LGPL
14918  * <script type="text/javascript">
14919  */
14920
14921
14922  
14923
14924 /**
14925  * @class Roo.MasterTemplate
14926  * @extends Roo.Template
14927  * Provides a template that can have child templates. The syntax is:
14928 <pre><code>
14929 var t = new Roo.MasterTemplate(
14930         '&lt;select name="{name}"&gt;',
14931                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
14932         '&lt;/select&gt;'
14933 );
14934 t.add('options', {value: 'foo', text: 'bar'});
14935 // or you can add multiple child elements in one shot
14936 t.addAll('options', [
14937     {value: 'foo', text: 'bar'},
14938     {value: 'foo2', text: 'bar2'},
14939     {value: 'foo3', text: 'bar3'}
14940 ]);
14941 // then append, applying the master template values
14942 t.append('my-form', {name: 'my-select'});
14943 </code></pre>
14944 * A name attribute for the child template is not required if you have only one child
14945 * template or you want to refer to them by index.
14946  */
14947 Roo.MasterTemplate = function(){
14948     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
14949     this.originalHtml = this.html;
14950     var st = {};
14951     var m, re = this.subTemplateRe;
14952     re.lastIndex = 0;
14953     var subIndex = 0;
14954     while(m = re.exec(this.html)){
14955         var name = m[1], content = m[2];
14956         st[subIndex] = {
14957             name: name,
14958             index: subIndex,
14959             buffer: [],
14960             tpl : new Roo.Template(content)
14961         };
14962         if(name){
14963             st[name] = st[subIndex];
14964         }
14965         st[subIndex].tpl.compile();
14966         st[subIndex].tpl.call = this.call.createDelegate(this);
14967         subIndex++;
14968     }
14969     this.subCount = subIndex;
14970     this.subs = st;
14971 };
14972 Roo.extend(Roo.MasterTemplate, Roo.Template, {
14973     /**
14974     * The regular expression used to match sub templates
14975     * @type RegExp
14976     * @property
14977     */
14978     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
14979
14980     /**
14981      * Applies the passed values to a child template.
14982      * @param {String/Number} name (optional) The name or index of the child template
14983      * @param {Array/Object} values The values to be applied to the template
14984      * @return {MasterTemplate} this
14985      */
14986      add : function(name, values){
14987         if(arguments.length == 1){
14988             values = arguments[0];
14989             name = 0;
14990         }
14991         var s = this.subs[name];
14992         s.buffer[s.buffer.length] = s.tpl.apply(values);
14993         return this;
14994     },
14995
14996     /**
14997      * Applies all the passed values to a child template.
14998      * @param {String/Number} name (optional) The name or index of the child template
14999      * @param {Array} values The values to be applied to the template, this should be an array of objects.
15000      * @param {Boolean} reset (optional) True to reset the template first
15001      * @return {MasterTemplate} this
15002      */
15003     fill : function(name, values, reset){
15004         var a = arguments;
15005         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
15006             values = a[0];
15007             name = 0;
15008             reset = a[1];
15009         }
15010         if(reset){
15011             this.reset();
15012         }
15013         for(var i = 0, len = values.length; i < len; i++){
15014             this.add(name, values[i]);
15015         }
15016         return this;
15017     },
15018
15019     /**
15020      * Resets the template for reuse
15021      * @return {MasterTemplate} this
15022      */
15023      reset : function(){
15024         var s = this.subs;
15025         for(var i = 0; i < this.subCount; i++){
15026             s[i].buffer = [];
15027         }
15028         return this;
15029     },
15030
15031     applyTemplate : function(values){
15032         var s = this.subs;
15033         var replaceIndex = -1;
15034         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
15035             return s[++replaceIndex].buffer.join("");
15036         });
15037         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
15038     },
15039
15040     apply : function(){
15041         return this.applyTemplate.apply(this, arguments);
15042     },
15043
15044     compile : function(){return this;}
15045 });
15046
15047 /**
15048  * Alias for fill().
15049  * @method
15050  */
15051 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
15052  /**
15053  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
15054  * var tpl = Roo.MasterTemplate.from('element-id');
15055  * @param {String/HTMLElement} el
15056  * @param {Object} config
15057  * @static
15058  */
15059 Roo.MasterTemplate.from = function(el, config){
15060     el = Roo.getDom(el);
15061     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
15062 };/*
15063  * Based on:
15064  * Ext JS Library 1.1.1
15065  * Copyright(c) 2006-2007, Ext JS, LLC.
15066  *
15067  * Originally Released Under LGPL - original licence link has changed is not relivant.
15068  *
15069  * Fork - LGPL
15070  * <script type="text/javascript">
15071  */
15072
15073  
15074 /**
15075  * @class Roo.util.CSS
15076  * Utility class for manipulating CSS rules
15077  * @static
15078
15079  */
15080 Roo.util.CSS = function(){
15081         var rules = null;
15082         var doc = document;
15083
15084     var camelRe = /(-[a-z])/gi;
15085     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
15086
15087    return {
15088    /**
15089     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
15090     * tag and appended to the HEAD of the document.
15091     * @param {String|Object} cssText The text containing the css rules
15092     * @param {String} id An id to add to the stylesheet for later removal
15093     * @return {StyleSheet}
15094     */
15095     createStyleSheet : function(cssText, id){
15096         var ss;
15097         var head = doc.getElementsByTagName("head")[0];
15098         var nrules = doc.createElement("style");
15099         nrules.setAttribute("type", "text/css");
15100         if(id){
15101             nrules.setAttribute("id", id);
15102         }
15103         if (typeof(cssText) != 'string') {
15104             // support object maps..
15105             // not sure if this a good idea.. 
15106             // perhaps it should be merged with the general css handling
15107             // and handle js style props.
15108             var cssTextNew = [];
15109             for(var n in cssText) {
15110                 var citems = [];
15111                 for(var k in cssText[n]) {
15112                     citems.push( k + ' : ' +cssText[n][k] + ';' );
15113                 }
15114                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
15115                 
15116             }
15117             cssText = cssTextNew.join("\n");
15118             
15119         }
15120        
15121        
15122        if(Roo.isIE){
15123            head.appendChild(nrules);
15124            ss = nrules.styleSheet;
15125            ss.cssText = cssText;
15126        }else{
15127            try{
15128                 nrules.appendChild(doc.createTextNode(cssText));
15129            }catch(e){
15130                nrules.cssText = cssText; 
15131            }
15132            head.appendChild(nrules);
15133            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
15134        }
15135        this.cacheStyleSheet(ss);
15136        return ss;
15137    },
15138
15139    /**
15140     * Removes a style or link tag by id
15141     * @param {String} id The id of the tag
15142     */
15143    removeStyleSheet : function(id){
15144        var existing = doc.getElementById(id);
15145        if(existing){
15146            existing.parentNode.removeChild(existing);
15147        }
15148    },
15149
15150    /**
15151     * Dynamically swaps an existing stylesheet reference for a new one
15152     * @param {String} id The id of an existing link tag to remove
15153     * @param {String} url The href of the new stylesheet to include
15154     */
15155    swapStyleSheet : function(id, url){
15156        this.removeStyleSheet(id);
15157        var ss = doc.createElement("link");
15158        ss.setAttribute("rel", "stylesheet");
15159        ss.setAttribute("type", "text/css");
15160        ss.setAttribute("id", id);
15161        ss.setAttribute("href", url);
15162        doc.getElementsByTagName("head")[0].appendChild(ss);
15163    },
15164    
15165    /**
15166     * Refresh the rule cache if you have dynamically added stylesheets
15167     * @return {Object} An object (hash) of rules indexed by selector
15168     */
15169    refreshCache : function(){
15170        return this.getRules(true);
15171    },
15172
15173    // private
15174    cacheStyleSheet : function(stylesheet){
15175        if(!rules){
15176            rules = {};
15177        }
15178        try{// try catch for cross domain access issue
15179            var ssRules = stylesheet.cssRules || stylesheet.rules;
15180            for(var j = ssRules.length-1; j >= 0; --j){
15181                rules[ssRules[j].selectorText] = ssRules[j];
15182            }
15183        }catch(e){}
15184    },
15185    
15186    /**
15187     * Gets all css rules for the document
15188     * @param {Boolean} refreshCache true to refresh the internal cache
15189     * @return {Object} An object (hash) of rules indexed by selector
15190     */
15191    getRules : function(refreshCache){
15192                 if(rules == null || refreshCache){
15193                         rules = {};
15194                         var ds = doc.styleSheets;
15195                         for(var i =0, len = ds.length; i < len; i++){
15196                             try{
15197                         this.cacheStyleSheet(ds[i]);
15198                     }catch(e){} 
15199                 }
15200                 }
15201                 return rules;
15202         },
15203         
15204         /**
15205     * Gets an an individual CSS rule by selector(s)
15206     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
15207     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
15208     * @return {CSSRule} The CSS rule or null if one is not found
15209     */
15210    getRule : function(selector, refreshCache){
15211                 var rs = this.getRules(refreshCache);
15212                 if(!(selector instanceof Array)){
15213                     return rs[selector];
15214                 }
15215                 for(var i = 0; i < selector.length; i++){
15216                         if(rs[selector[i]]){
15217                                 return rs[selector[i]];
15218                         }
15219                 }
15220                 return null;
15221         },
15222         
15223         
15224         /**
15225     * Updates a rule property
15226     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
15227     * @param {String} property The css property
15228     * @param {String} value The new value for the property
15229     * @return {Boolean} true If a rule was found and updated
15230     */
15231    updateRule : function(selector, property, value){
15232                 if(!(selector instanceof Array)){
15233                         var rule = this.getRule(selector);
15234                         if(rule){
15235                                 rule.style[property.replace(camelRe, camelFn)] = value;
15236                                 return true;
15237                         }
15238                 }else{
15239                         for(var i = 0; i < selector.length; i++){
15240                                 if(this.updateRule(selector[i], property, value)){
15241                                         return true;
15242                                 }
15243                         }
15244                 }
15245                 return false;
15246         }
15247    };   
15248 }();/*
15249  * Based on:
15250  * Ext JS Library 1.1.1
15251  * Copyright(c) 2006-2007, Ext JS, LLC.
15252  *
15253  * Originally Released Under LGPL - original licence link has changed is not relivant.
15254  *
15255  * Fork - LGPL
15256  * <script type="text/javascript">
15257  */
15258
15259  
15260
15261 /**
15262  * @class Roo.util.ClickRepeater
15263  * @extends Roo.util.Observable
15264  * 
15265  * A wrapper class which can be applied to any element. Fires a "click" event while the
15266  * mouse is pressed. The interval between firings may be specified in the config but
15267  * defaults to 10 milliseconds.
15268  * 
15269  * Optionally, a CSS class may be applied to the element during the time it is pressed.
15270  * 
15271  * @cfg {String/HTMLElement/Element} el The element to act as a button.
15272  * @cfg {Number} delay The initial delay before the repeating event begins firing.
15273  * Similar to an autorepeat key delay.
15274  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
15275  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
15276  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
15277  *           "interval" and "delay" are ignored. "immediate" is honored.
15278  * @cfg {Boolean} preventDefault True to prevent the default click event
15279  * @cfg {Boolean} stopDefault True to stop the default click event
15280  * 
15281  * @history
15282  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
15283  *     2007-02-02 jvs Renamed to ClickRepeater
15284  *   2007-02-03 jvs Modifications for FF Mac and Safari 
15285  *
15286  *  @constructor
15287  * @param {String/HTMLElement/Element} el The element to listen on
15288  * @param {Object} config
15289  **/
15290 Roo.util.ClickRepeater = function(el, config)
15291 {
15292     this.el = Roo.get(el);
15293     this.el.unselectable();
15294
15295     Roo.apply(this, config);
15296
15297     this.addEvents({
15298     /**
15299      * @event mousedown
15300      * Fires when the mouse button is depressed.
15301      * @param {Roo.util.ClickRepeater} this
15302      */
15303         "mousedown" : true,
15304     /**
15305      * @event click
15306      * Fires on a specified interval during the time the element is pressed.
15307      * @param {Roo.util.ClickRepeater} this
15308      */
15309         "click" : true,
15310     /**
15311      * @event mouseup
15312      * Fires when the mouse key is released.
15313      * @param {Roo.util.ClickRepeater} this
15314      */
15315         "mouseup" : true
15316     });
15317
15318     this.el.on("mousedown", this.handleMouseDown, this);
15319     if(this.preventDefault || this.stopDefault){
15320         this.el.on("click", function(e){
15321             if(this.preventDefault){
15322                 e.preventDefault();
15323             }
15324             if(this.stopDefault){
15325                 e.stopEvent();
15326             }
15327         }, this);
15328     }
15329
15330     // allow inline handler
15331     if(this.handler){
15332         this.on("click", this.handler,  this.scope || this);
15333     }
15334
15335     Roo.util.ClickRepeater.superclass.constructor.call(this);
15336 };
15337
15338 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
15339     interval : 20,
15340     delay: 250,
15341     preventDefault : true,
15342     stopDefault : false,
15343     timer : 0,
15344
15345     // private
15346     handleMouseDown : function(){
15347         clearTimeout(this.timer);
15348         this.el.blur();
15349         if(this.pressClass){
15350             this.el.addClass(this.pressClass);
15351         }
15352         this.mousedownTime = new Date();
15353
15354         Roo.get(document).on("mouseup", this.handleMouseUp, this);
15355         this.el.on("mouseout", this.handleMouseOut, this);
15356
15357         this.fireEvent("mousedown", this);
15358         this.fireEvent("click", this);
15359         
15360         this.timer = this.click.defer(this.delay || this.interval, this);
15361     },
15362
15363     // private
15364     click : function(){
15365         this.fireEvent("click", this);
15366         this.timer = this.click.defer(this.getInterval(), this);
15367     },
15368
15369     // private
15370     getInterval: function(){
15371         if(!this.accelerate){
15372             return this.interval;
15373         }
15374         var pressTime = this.mousedownTime.getElapsed();
15375         if(pressTime < 500){
15376             return 400;
15377         }else if(pressTime < 1700){
15378             return 320;
15379         }else if(pressTime < 2600){
15380             return 250;
15381         }else if(pressTime < 3500){
15382             return 180;
15383         }else if(pressTime < 4400){
15384             return 140;
15385         }else if(pressTime < 5300){
15386             return 80;
15387         }else if(pressTime < 6200){
15388             return 50;
15389         }else{
15390             return 10;
15391         }
15392     },
15393
15394     // private
15395     handleMouseOut : function(){
15396         clearTimeout(this.timer);
15397         if(this.pressClass){
15398             this.el.removeClass(this.pressClass);
15399         }
15400         this.el.on("mouseover", this.handleMouseReturn, this);
15401     },
15402
15403     // private
15404     handleMouseReturn : function(){
15405         this.el.un("mouseover", this.handleMouseReturn);
15406         if(this.pressClass){
15407             this.el.addClass(this.pressClass);
15408         }
15409         this.click();
15410     },
15411
15412     // private
15413     handleMouseUp : function(){
15414         clearTimeout(this.timer);
15415         this.el.un("mouseover", this.handleMouseReturn);
15416         this.el.un("mouseout", this.handleMouseOut);
15417         Roo.get(document).un("mouseup", this.handleMouseUp);
15418         this.el.removeClass(this.pressClass);
15419         this.fireEvent("mouseup", this);
15420     }
15421 });/**
15422  * @class Roo.util.Clipboard
15423  * @static
15424  * 
15425  * Clipboard UTILS
15426  * 
15427  **/
15428 Roo.util.Clipboard = {
15429     /**
15430      * Writes a string to the clipboard - using the Clipboard API if https, otherwise using text area.
15431      * @param {String} text to copy to clipboard
15432      */
15433     write : function(text) {
15434         // navigator clipboard api needs a secure context (https)
15435         if (navigator.clipboard && window.isSecureContext) {
15436             // navigator clipboard api method'
15437             navigator.clipboard.writeText(text);
15438             return ;
15439         } 
15440         // text area method
15441         var ta = document.createElement("textarea");
15442         ta.value = text;
15443         // make the textarea out of viewport
15444         ta.style.position = "fixed";
15445         ta.style.left = "-999999px";
15446         ta.style.top = "-999999px";
15447         document.body.appendChild(ta);
15448         ta.focus();
15449         ta.select();
15450         document.execCommand('copy');
15451         (function() {
15452             ta.remove();
15453         }).defer(100);
15454         
15455     }
15456         
15457 }
15458     /*
15459  * Based on:
15460  * Ext JS Library 1.1.1
15461  * Copyright(c) 2006-2007, Ext JS, LLC.
15462  *
15463  * Originally Released Under LGPL - original licence link has changed is not relivant.
15464  *
15465  * Fork - LGPL
15466  * <script type="text/javascript">
15467  */
15468
15469  
15470 /**
15471  * @class Roo.KeyNav
15472  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
15473  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
15474  * way to implement custom navigation schemes for any UI component.</p>
15475  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
15476  * pageUp, pageDown, del, home, end.  Usage:</p>
15477  <pre><code>
15478 var nav = new Roo.KeyNav("my-element", {
15479     "left" : function(e){
15480         this.moveLeft(e.ctrlKey);
15481     },
15482     "right" : function(e){
15483         this.moveRight(e.ctrlKey);
15484     },
15485     "enter" : function(e){
15486         this.save();
15487     },
15488     scope : this
15489 });
15490 </code></pre>
15491  * @constructor
15492  * @param {String/HTMLElement/Roo.Element} el The element to bind to
15493  * @param {Object} config The config
15494  */
15495 Roo.KeyNav = function(el, config){
15496     this.el = Roo.get(el);
15497     Roo.apply(this, config);
15498     if(!this.disabled){
15499         this.disabled = true;
15500         this.enable();
15501     }
15502 };
15503
15504 Roo.KeyNav.prototype = {
15505     /**
15506      * @cfg {Boolean} disabled
15507      * True to disable this KeyNav instance (defaults to false)
15508      */
15509     disabled : false,
15510     /**
15511      * @cfg {String} defaultEventAction
15512      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
15513      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
15514      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
15515      */
15516     defaultEventAction: "stopEvent",
15517     /**
15518      * @cfg {Boolean} forceKeyDown
15519      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
15520      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
15521      * handle keydown instead of keypress.
15522      */
15523     forceKeyDown : false,
15524
15525     // private
15526     prepareEvent : function(e){
15527         var k = e.getKey();
15528         var h = this.keyToHandler[k];
15529         //if(h && this[h]){
15530         //    e.stopPropagation();
15531         //}
15532         if(Roo.isSafari && h && k >= 37 && k <= 40){
15533             e.stopEvent();
15534         }
15535     },
15536
15537     // private
15538     relay : function(e){
15539         var k = e.getKey();
15540         var h = this.keyToHandler[k];
15541         if(h && this[h]){
15542             if(this.doRelay(e, this[h], h) !== true){
15543                 e[this.defaultEventAction]();
15544             }
15545         }
15546     },
15547
15548     // private
15549     doRelay : function(e, h, hname){
15550         return h.call(this.scope || this, e);
15551     },
15552
15553     // possible handlers
15554     enter : false,
15555     left : false,
15556     right : false,
15557     up : false,
15558     down : false,
15559     tab : false,
15560     esc : false,
15561     pageUp : false,
15562     pageDown : false,
15563     del : false,
15564     home : false,
15565     end : false,
15566
15567     // quick lookup hash
15568     keyToHandler : {
15569         37 : "left",
15570         39 : "right",
15571         38 : "up",
15572         40 : "down",
15573         33 : "pageUp",
15574         34 : "pageDown",
15575         46 : "del",
15576         36 : "home",
15577         35 : "end",
15578         13 : "enter",
15579         27 : "esc",
15580         9  : "tab"
15581     },
15582
15583         /**
15584          * Enable this KeyNav
15585          */
15586         enable: function(){
15587                 if(this.disabled){
15588             // ie won't do special keys on keypress, no one else will repeat keys with keydown
15589             // the EventObject will normalize Safari automatically
15590             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
15591                 this.el.on("keydown", this.relay,  this);
15592             }else{
15593                 this.el.on("keydown", this.prepareEvent,  this);
15594                 this.el.on("keypress", this.relay,  this);
15595             }
15596                     this.disabled = false;
15597                 }
15598         },
15599
15600         /**
15601          * Disable this KeyNav
15602          */
15603         disable: function(){
15604                 if(!this.disabled){
15605                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
15606                 this.el.un("keydown", this.relay);
15607             }else{
15608                 this.el.un("keydown", this.prepareEvent);
15609                 this.el.un("keypress", this.relay);
15610             }
15611                     this.disabled = true;
15612                 }
15613         }
15614 };/*
15615  * Based on:
15616  * Ext JS Library 1.1.1
15617  * Copyright(c) 2006-2007, Ext JS, LLC.
15618  *
15619  * Originally Released Under LGPL - original licence link has changed is not relivant.
15620  *
15621  * Fork - LGPL
15622  * <script type="text/javascript">
15623  */
15624
15625  
15626 /**
15627  * @class Roo.KeyMap
15628  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
15629  * The constructor accepts the same config object as defined by {@link #addBinding}.
15630  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
15631  * combination it will call the function with this signature (if the match is a multi-key
15632  * combination the callback will still be called only once): (String key, Roo.EventObject e)
15633  * A KeyMap can also handle a string representation of keys.<br />
15634  * Usage:
15635  <pre><code>
15636 // map one key by key code
15637 var map = new Roo.KeyMap("my-element", {
15638     key: 13, // or Roo.EventObject.ENTER
15639     fn: myHandler,
15640     scope: myObject
15641 });
15642
15643 // map multiple keys to one action by string
15644 var map = new Roo.KeyMap("my-element", {
15645     key: "a\r\n\t",
15646     fn: myHandler,
15647     scope: myObject
15648 });
15649
15650 // map multiple keys to multiple actions by strings and array of codes
15651 var map = new Roo.KeyMap("my-element", [
15652     {
15653         key: [10,13],
15654         fn: function(){ alert("Return was pressed"); }
15655     }, {
15656         key: "abc",
15657         fn: function(){ alert('a, b or c was pressed'); }
15658     }, {
15659         key: "\t",
15660         ctrl:true,
15661         shift:true,
15662         fn: function(){ alert('Control + shift + tab was pressed.'); }
15663     }
15664 ]);
15665 </code></pre>
15666  * <b>Note: A KeyMap starts enabled</b>
15667  * @constructor
15668  * @param {String/HTMLElement/Roo.Element} el The element to bind to
15669  * @param {Object} config The config (see {@link #addBinding})
15670  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
15671  */
15672 Roo.KeyMap = function(el, config, eventName){
15673     this.el  = Roo.get(el);
15674     this.eventName = eventName || "keydown";
15675     this.bindings = [];
15676     if(config){
15677         this.addBinding(config);
15678     }
15679     this.enable();
15680 };
15681
15682 Roo.KeyMap.prototype = {
15683     /**
15684      * True to stop the event from bubbling and prevent the default browser action if the
15685      * key was handled by the KeyMap (defaults to false)
15686      * @type Boolean
15687      */
15688     stopEvent : false,
15689
15690     /**
15691      * Add a new binding to this KeyMap. The following config object properties are supported:
15692      * <pre>
15693 Property    Type             Description
15694 ----------  ---------------  ----------------------------------------------------------------------
15695 key         String/Array     A single keycode or an array of keycodes to handle
15696 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
15697 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
15698 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
15699 fn          Function         The function to call when KeyMap finds the expected key combination
15700 scope       Object           The scope of the callback function
15701 </pre>
15702      *
15703      * Usage:
15704      * <pre><code>
15705 // Create a KeyMap
15706 var map = new Roo.KeyMap(document, {
15707     key: Roo.EventObject.ENTER,
15708     fn: handleKey,
15709     scope: this
15710 });
15711
15712 //Add a new binding to the existing KeyMap later
15713 map.addBinding({
15714     key: 'abc',
15715     shift: true,
15716     fn: handleKey,
15717     scope: this
15718 });
15719 </code></pre>
15720      * @param {Object/Array} config A single KeyMap config or an array of configs
15721      */
15722         addBinding : function(config){
15723         if(config instanceof Array){
15724             for(var i = 0, len = config.length; i < len; i++){
15725                 this.addBinding(config[i]);
15726             }
15727             return;
15728         }
15729         var keyCode = config.key,
15730             shift = config.shift, 
15731             ctrl = config.ctrl, 
15732             alt = config.alt,
15733             fn = config.fn,
15734             scope = config.scope;
15735         if(typeof keyCode == "string"){
15736             var ks = [];
15737             var keyString = keyCode.toUpperCase();
15738             for(var j = 0, len = keyString.length; j < len; j++){
15739                 ks.push(keyString.charCodeAt(j));
15740             }
15741             keyCode = ks;
15742         }
15743         var keyArray = keyCode instanceof Array;
15744         var handler = function(e){
15745             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
15746                 var k = e.getKey();
15747                 if(keyArray){
15748                     for(var i = 0, len = keyCode.length; i < len; i++){
15749                         if(keyCode[i] == k){
15750                           if(this.stopEvent){
15751                               e.stopEvent();
15752                           }
15753                           fn.call(scope || window, k, e);
15754                           return;
15755                         }
15756                     }
15757                 }else{
15758                     if(k == keyCode){
15759                         if(this.stopEvent){
15760                            e.stopEvent();
15761                         }
15762                         fn.call(scope || window, k, e);
15763                     }
15764                 }
15765             }
15766         };
15767         this.bindings.push(handler);  
15768         },
15769
15770     /**
15771      * Shorthand for adding a single key listener
15772      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
15773      * following options:
15774      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
15775      * @param {Function} fn The function to call
15776      * @param {Object} scope (optional) The scope of the function
15777      */
15778     on : function(key, fn, scope){
15779         var keyCode, shift, ctrl, alt;
15780         if(typeof key == "object" && !(key instanceof Array)){
15781             keyCode = key.key;
15782             shift = key.shift;
15783             ctrl = key.ctrl;
15784             alt = key.alt;
15785         }else{
15786             keyCode = key;
15787         }
15788         this.addBinding({
15789             key: keyCode,
15790             shift: shift,
15791             ctrl: ctrl,
15792             alt: alt,
15793             fn: fn,
15794             scope: scope
15795         })
15796     },
15797
15798     // private
15799     handleKeyDown : function(e){
15800             if(this.enabled){ //just in case
15801             var b = this.bindings;
15802             for(var i = 0, len = b.length; i < len; i++){
15803                 b[i].call(this, e);
15804             }
15805             }
15806         },
15807         
15808         /**
15809          * Returns true if this KeyMap is enabled
15810          * @return {Boolean} 
15811          */
15812         isEnabled : function(){
15813             return this.enabled;  
15814         },
15815         
15816         /**
15817          * Enables this KeyMap
15818          */
15819         enable: function(){
15820                 if(!this.enabled){
15821                     this.el.on(this.eventName, this.handleKeyDown, this);
15822                     this.enabled = true;
15823                 }
15824         },
15825
15826         /**
15827          * Disable this KeyMap
15828          */
15829         disable: function(){
15830                 if(this.enabled){
15831                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
15832                     this.enabled = false;
15833                 }
15834         }
15835 };/*
15836  * Based on:
15837  * Ext JS Library 1.1.1
15838  * Copyright(c) 2006-2007, Ext JS, LLC.
15839  *
15840  * Originally Released Under LGPL - original licence link has changed is not relivant.
15841  *
15842  * Fork - LGPL
15843  * <script type="text/javascript">
15844  */
15845
15846  
15847 /**
15848  * @class Roo.util.TextMetrics
15849  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
15850  * wide, in pixels, a given block of text will be.
15851  * @static
15852  */
15853 Roo.util.TextMetrics = function(){
15854     var shared;
15855     return {
15856         /**
15857          * Measures the size of the specified text
15858          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
15859          * that can affect the size of the rendered text
15860          * @param {String} text The text to measure
15861          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
15862          * in order to accurately measure the text height
15863          * @return {Object} An object containing the text's size {width: (width), height: (height)}
15864          */
15865         measure : function(el, text, fixedWidth){
15866             if(!shared){
15867                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
15868             }
15869             shared.bind(el);
15870             shared.setFixedWidth(fixedWidth || 'auto');
15871             return shared.getSize(text);
15872         },
15873
15874         /**
15875          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
15876          * the overhead of multiple calls to initialize the style properties on each measurement.
15877          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
15878          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
15879          * in order to accurately measure the text height
15880          * @return {Roo.util.TextMetrics.Instance} instance The new instance
15881          */
15882         createInstance : function(el, fixedWidth){
15883             return Roo.util.TextMetrics.Instance(el, fixedWidth);
15884         }
15885     };
15886 }();
15887
15888 /**
15889  * @class Roo.util.TextMetrics.Instance
15890  * Instance of  TextMetrics Calcuation
15891  * @constructor
15892  * Create a new TextMetrics Instance
15893  * @param {Object} bindto
15894  * @param {Boolean} fixedWidth
15895  */
15896
15897 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth)
15898 {
15899     var ml = new Roo.Element(document.createElement('div'));
15900     document.body.appendChild(ml.dom);
15901     ml.position('absolute');
15902     ml.setLeftTop(-1000, -1000);
15903     ml.hide();
15904
15905     if(fixedWidth){
15906         ml.setWidth(fixedWidth);
15907     }
15908      
15909     var instance = {
15910         /**
15911          * Returns the size of the specified text based on the internal element's style and width properties
15912          * @param {String} text The text to measure
15913          * @return {Object} An object containing the text's size {width: (width), height: (height)}
15914          */
15915         getSize : function(text){
15916             ml.update(text);
15917             var s = ml.getSize();
15918             ml.update('');
15919             return s;
15920         },
15921
15922         /**
15923          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
15924          * that can affect the size of the rendered text
15925          * @param {String/HTMLElement} el The element, dom node or id
15926          */
15927         bind : function(el){
15928             ml.setStyle(
15929                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
15930             );
15931         },
15932
15933         /**
15934          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
15935          * to set a fixed width in order to accurately measure the text height.
15936          * @param {Number} width The width to set on the element
15937          */
15938         setFixedWidth : function(width){
15939             ml.setWidth(width);
15940         },
15941
15942         /**
15943          * Returns the measured width of the specified text
15944          * @param {String} text The text to measure
15945          * @return {Number} width The width in pixels
15946          */
15947         getWidth : function(text){
15948             ml.dom.style.width = 'auto';
15949             return this.getSize(text).width;
15950         },
15951
15952         /**
15953          * Returns the measured height of the specified text.  For multiline text, be sure to call
15954          * {@link #setFixedWidth} if necessary.
15955          * @param {String} text The text to measure
15956          * @return {Number} height The height in pixels
15957          */
15958         getHeight : function(text){
15959             return this.getSize(text).height;
15960         }
15961     };
15962
15963     instance.bind(bindTo);
15964
15965     return instance;
15966 };
15967
15968 // backwards compat
15969 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
15970  * Based on:
15971  * Ext JS Library 1.1.1
15972  * Copyright(c) 2006-2007, Ext JS, LLC.
15973  *
15974  * Originally Released Under LGPL - original licence link has changed is not relivant.
15975  *
15976  * Fork - LGPL
15977  * <script type="text/javascript">
15978  */
15979
15980 /**
15981  * @class Roo.state.Provider
15982  * Abstract base class for state provider implementations. This class provides methods
15983  * for encoding and decoding <b>typed</b> variables including dates and defines the 
15984  * Provider interface.
15985  */
15986 Roo.state.Provider = function(){
15987     /**
15988      * @event statechange
15989      * Fires when a state change occurs.
15990      * @param {Provider} this This state provider
15991      * @param {String} key The state key which was changed
15992      * @param {String} value The encoded value for the state
15993      */
15994     this.addEvents({
15995         "statechange": true
15996     });
15997     this.state = {};
15998     Roo.state.Provider.superclass.constructor.call(this);
15999 };
16000 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
16001     /**
16002      * Returns the current value for a key
16003      * @param {String} name The key name
16004      * @param {Mixed} defaultValue A default value to return if the key's value is not found
16005      * @return {Mixed} The state data
16006      */
16007     get : function(name, defaultValue){
16008         return typeof this.state[name] == "undefined" ?
16009             defaultValue : this.state[name];
16010     },
16011     
16012     /**
16013      * Clears a value from the state
16014      * @param {String} name The key name
16015      */
16016     clear : function(name){
16017         delete this.state[name];
16018         this.fireEvent("statechange", this, name, null);
16019     },
16020     
16021     /**
16022      * Sets the value for a key
16023      * @param {String} name The key name
16024      * @param {Mixed} value The value to set
16025      */
16026     set : function(name, value){
16027         this.state[name] = value;
16028         this.fireEvent("statechange", this, name, value);
16029     },
16030     
16031     /**
16032      * Decodes a string previously encoded with {@link #encodeValue}.
16033      * @param {String} value The value to decode
16034      * @return {Mixed} The decoded value
16035      */
16036     decodeValue : function(cookie){
16037         var re = /^(a|n|d|b|s|o)\:(.*)$/;
16038         var matches = re.exec(unescape(cookie));
16039         if(!matches || !matches[1]) {
16040             return; // non state cookie
16041         }
16042         var type = matches[1];
16043         var v = matches[2];
16044         switch(type){
16045             case "n":
16046                 return parseFloat(v);
16047             case "d":
16048                 return new Date(Date.parse(v));
16049             case "b":
16050                 return (v == "1");
16051             case "a":
16052                 var all = [];
16053                 var values = v.split("^");
16054                 for(var i = 0, len = values.length; i < len; i++){
16055                     all.push(this.decodeValue(values[i]));
16056                 }
16057                 return all;
16058            case "o":
16059                 var all = {};
16060                 var values = v.split("^");
16061                 for(var i = 0, len = values.length; i < len; i++){
16062                     var kv = values[i].split("=");
16063                     all[kv[0]] = this.decodeValue(kv[1]);
16064                 }
16065                 return all;
16066            default:
16067                 return v;
16068         }
16069     },
16070     
16071     /**
16072      * Encodes a value including type information.  Decode with {@link #decodeValue}.
16073      * @param {Mixed} value The value to encode
16074      * @return {String} The encoded value
16075      */
16076     encodeValue : function(v){
16077         var enc;
16078         if(typeof v == "number"){
16079             enc = "n:" + v;
16080         }else if(typeof v == "boolean"){
16081             enc = "b:" + (v ? "1" : "0");
16082         }else if(v instanceof Date){
16083             enc = "d:" + v.toGMTString();
16084         }else if(v instanceof Array){
16085             var flat = "";
16086             for(var i = 0, len = v.length; i < len; i++){
16087                 flat += this.encodeValue(v[i]);
16088                 if(i != len-1) {
16089                     flat += "^";
16090                 }
16091             }
16092             enc = "a:" + flat;
16093         }else if(typeof v == "object"){
16094             var flat = "";
16095             for(var key in v){
16096                 if(typeof v[key] != "function"){
16097                     flat += key + "=" + this.encodeValue(v[key]) + "^";
16098                 }
16099             }
16100             enc = "o:" + flat.substring(0, flat.length-1);
16101         }else{
16102             enc = "s:" + v;
16103         }
16104         return escape(enc);        
16105     }
16106 });
16107
16108 /*
16109  * Based on:
16110  * Ext JS Library 1.1.1
16111  * Copyright(c) 2006-2007, Ext JS, LLC.
16112  *
16113  * Originally Released Under LGPL - original licence link has changed is not relivant.
16114  *
16115  * Fork - LGPL
16116  * <script type="text/javascript">
16117  */
16118 /**
16119  * @class Roo.state.Manager
16120  * This is the global state manager. By default all components that are "state aware" check this class
16121  * for state information if you don't pass them a custom state provider. In order for this class
16122  * to be useful, it must be initialized with a provider when your application initializes.
16123  <pre><code>
16124 // in your initialization function
16125 init : function(){
16126    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
16127    ...
16128    // supposed you have a {@link Roo.BorderLayout}
16129    var layout = new Roo.BorderLayout(...);
16130    layout.restoreState();
16131    // or a {Roo.BasicDialog}
16132    var dialog = new Roo.BasicDialog(...);
16133    dialog.restoreState();
16134  </code></pre>
16135  * @static
16136  */
16137 Roo.state.Manager = function(){
16138     var provider = new Roo.state.Provider();
16139     
16140     return {
16141         /**
16142          * Configures the default state provider for your application
16143          * @param {Provider} stateProvider The state provider to set
16144          */
16145         setProvider : function(stateProvider){
16146             provider = stateProvider;
16147         },
16148         
16149         /**
16150          * Returns the current value for a key
16151          * @param {String} name The key name
16152          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
16153          * @return {Mixed} The state data
16154          */
16155         get : function(key, defaultValue){
16156             return provider.get(key, defaultValue);
16157         },
16158         
16159         /**
16160          * Sets the value for a key
16161          * @param {String} name The key name
16162          * @param {Mixed} value The state data
16163          */
16164          set : function(key, value){
16165             provider.set(key, value);
16166         },
16167         
16168         /**
16169          * Clears a value from the state
16170          * @param {String} name The key name
16171          */
16172         clear : function(key){
16173             provider.clear(key);
16174         },
16175         
16176         /**
16177          * Gets the currently configured state provider
16178          * @return {Provider} The state provider
16179          */
16180         getProvider : function(){
16181             return provider;
16182         }
16183     };
16184 }();
16185 /*
16186  * Based on:
16187  * Ext JS Library 1.1.1
16188  * Copyright(c) 2006-2007, Ext JS, LLC.
16189  *
16190  * Originally Released Under LGPL - original licence link has changed is not relivant.
16191  *
16192  * Fork - LGPL
16193  * <script type="text/javascript">
16194  */
16195 /**
16196  * @class Roo.state.CookieProvider
16197  * @extends Roo.state.Provider
16198  * The default Provider implementation which saves state via cookies.
16199  * <br />Usage:
16200  <pre><code>
16201    var cp = new Roo.state.CookieProvider({
16202        path: "/cgi-bin/",
16203        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
16204        domain: "roojs.com"
16205    })
16206    Roo.state.Manager.setProvider(cp);
16207  </code></pre>
16208  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
16209  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
16210  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
16211  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
16212  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
16213  * domain the page is running on including the 'www' like 'www.roojs.com')
16214  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
16215  * @constructor
16216  * Create a new CookieProvider
16217  * @param {Object} config The configuration object
16218  */
16219 Roo.state.CookieProvider = function(config){
16220     Roo.state.CookieProvider.superclass.constructor.call(this);
16221     this.path = "/";
16222     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
16223     this.domain = null;
16224     this.secure = false;
16225     Roo.apply(this, config);
16226     this.state = this.readCookies();
16227 };
16228
16229 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
16230     // private
16231     set : function(name, value){
16232         if(typeof value == "undefined" || value === null){
16233             this.clear(name);
16234             return;
16235         }
16236         this.setCookie(name, value);
16237         Roo.state.CookieProvider.superclass.set.call(this, name, value);
16238     },
16239
16240     // private
16241     clear : function(name){
16242         this.clearCookie(name);
16243         Roo.state.CookieProvider.superclass.clear.call(this, name);
16244     },
16245
16246     // private
16247     readCookies : function(){
16248         var cookies = {};
16249         var c = document.cookie + ";";
16250         var re = /\s?(.*?)=(.*?);/g;
16251         var matches;
16252         while((matches = re.exec(c)) != null){
16253             var name = matches[1];
16254             var value = matches[2];
16255             if(name && name.substring(0,3) == "ys-"){
16256                 cookies[name.substr(3)] = this.decodeValue(value);
16257             }
16258         }
16259         return cookies;
16260     },
16261
16262     // private
16263     setCookie : function(name, value){
16264         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
16265            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
16266            ((this.path == null) ? "" : ("; path=" + this.path)) +
16267            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
16268            ((this.secure == true) ? "; secure" : "");
16269     },
16270
16271     // private
16272     clearCookie : function(name){
16273         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
16274            ((this.path == null) ? "" : ("; path=" + this.path)) +
16275            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
16276            ((this.secure == true) ? "; secure" : "");
16277     }
16278 });/*
16279  * Based on:
16280  * Ext JS Library 1.1.1
16281  * Copyright(c) 2006-2007, Ext JS, LLC.
16282  *
16283  * Originally Released Under LGPL - original licence link has changed is not relivant.
16284  *
16285  * Fork - LGPL
16286  * <script type="text/javascript">
16287  */
16288  
16289
16290 /**
16291  * @class Roo.ComponentMgr
16292  * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
16293  * @static
16294  */
16295 Roo.ComponentMgr = function(){
16296     var all = new Roo.util.MixedCollection();
16297
16298     return {
16299         /**
16300          * Registers a component.
16301          * @param {Roo.Component} c The component
16302          */
16303         register : function(c){
16304             all.add(c);
16305         },
16306
16307         /**
16308          * Unregisters a component.
16309          * @param {Roo.Component} c The component
16310          */
16311         unregister : function(c){
16312             all.remove(c);
16313         },
16314
16315         /**
16316          * Returns a component by id
16317          * @param {String} id The component id
16318          */
16319         get : function(id){
16320             return all.get(id);
16321         },
16322
16323         /**
16324          * Registers a function that will be called when a specified component is added to ComponentMgr
16325          * @param {String} id The component id
16326          * @param {Funtction} fn The callback function
16327          * @param {Object} scope The scope of the callback
16328          */
16329         onAvailable : function(id, fn, scope){
16330             all.on("add", function(index, o){
16331                 if(o.id == id){
16332                     fn.call(scope || o, o);
16333                     all.un("add", fn, scope);
16334                 }
16335             });
16336         }
16337     };
16338 }();/*
16339  * Based on:
16340  * Ext JS Library 1.1.1
16341  * Copyright(c) 2006-2007, Ext JS, LLC.
16342  *
16343  * Originally Released Under LGPL - original licence link has changed is not relivant.
16344  *
16345  * Fork - LGPL
16346  * <script type="text/javascript">
16347  */
16348  
16349 /**
16350  * @class Roo.Component
16351  * @extends Roo.util.Observable
16352  * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
16353  * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
16354  * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
16355  * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
16356  * All visual components (widgets) that require rendering into a layout should subclass Component.
16357  * @constructor
16358  * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
16359  * 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
16360  * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
16361  */
16362 Roo.Component = function(config){
16363     config = config || {};
16364     if(config.tagName || config.dom || typeof config == "string"){ // element object
16365         config = {el: config, id: config.id || config};
16366     }
16367     this.initialConfig = config;
16368
16369     Roo.apply(this, config);
16370     this.addEvents({
16371         /**
16372          * @event disable
16373          * Fires after the component is disabled.
16374              * @param {Roo.Component} this
16375              */
16376         disable : true,
16377         /**
16378          * @event enable
16379          * Fires after the component is enabled.
16380              * @param {Roo.Component} this
16381              */
16382         enable : true,
16383         /**
16384          * @event beforeshow
16385          * Fires before the component is shown.  Return false to stop the show.
16386              * @param {Roo.Component} this
16387              */
16388         beforeshow : true,
16389         /**
16390          * @event show
16391          * Fires after the component is shown.
16392              * @param {Roo.Component} this
16393              */
16394         show : true,
16395         /**
16396          * @event beforehide
16397          * Fires before the component is hidden. Return false to stop the hide.
16398              * @param {Roo.Component} this
16399              */
16400         beforehide : true,
16401         /**
16402          * @event hide
16403          * Fires after the component is hidden.
16404              * @param {Roo.Component} this
16405              */
16406         hide : true,
16407         /**
16408          * @event beforerender
16409          * Fires before the component is rendered. Return false to stop the render.
16410              * @param {Roo.Component} this
16411              */
16412         beforerender : true,
16413         /**
16414          * @event render
16415          * Fires after the component is rendered.
16416              * @param {Roo.Component} this
16417              */
16418         render : true,
16419         /**
16420          * @event beforedestroy
16421          * Fires before the component is destroyed. Return false to stop the destroy.
16422              * @param {Roo.Component} this
16423              */
16424         beforedestroy : true,
16425         /**
16426          * @event destroy
16427          * Fires after the component is destroyed.
16428              * @param {Roo.Component} this
16429              */
16430         destroy : true
16431     });
16432     if(!this.id){
16433         this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
16434     }
16435     Roo.ComponentMgr.register(this);
16436     Roo.Component.superclass.constructor.call(this);
16437     this.initComponent();
16438     if(this.renderTo){ // not supported by all components yet. use at your own risk!
16439         this.render(this.renderTo);
16440         delete this.renderTo;
16441     }
16442 };
16443
16444 /** @private */
16445 Roo.Component.AUTO_ID = 1000;
16446
16447 Roo.extend(Roo.Component, Roo.util.Observable, {
16448     /**
16449      * @scope Roo.Component.prototype
16450      * @type {Boolean}
16451      * true if this component is hidden. Read-only.
16452      */
16453     hidden : false,
16454     /**
16455      * @type {Boolean}
16456      * true if this component is disabled. Read-only.
16457      */
16458     disabled : false,
16459     /**
16460      * @type {Boolean}
16461      * true if this component has been rendered. Read-only.
16462      */
16463     rendered : false,
16464     
16465     /** @cfg {String} disableClass
16466      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
16467      */
16468     disabledClass : "x-item-disabled",
16469         /** @cfg {Boolean} allowDomMove
16470          * Whether the component can move the Dom node when rendering (defaults to true).
16471          */
16472     allowDomMove : true,
16473     /** @cfg {String} hideMode (display|visibility)
16474      * How this component should hidden. Supported values are
16475      * "visibility" (css visibility), "offsets" (negative offset position) and
16476      * "display" (css display) - defaults to "display".
16477      */
16478     hideMode: 'display',
16479
16480     /** @private */
16481     ctype : "Roo.Component",
16482
16483     /**
16484      * @cfg {String} actionMode 
16485      * which property holds the element that used for  hide() / show() / disable() / enable()
16486      * default is 'el' for forms you probably want to set this to fieldEl 
16487      */
16488     actionMode : "el",
16489
16490     /** @private */
16491     getActionEl : function(){
16492         return this[this.actionMode];
16493     },
16494
16495     initComponent : Roo.emptyFn,
16496     /**
16497      * If this is a lazy rendering component, render it to its container element.
16498      * @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.
16499      */
16500     render : function(container, position){
16501         
16502         if(this.rendered){
16503             return this;
16504         }
16505         
16506         if(this.fireEvent("beforerender", this) === false){
16507             return false;
16508         }
16509         
16510         if(!container && this.el){
16511             this.el = Roo.get(this.el);
16512             container = this.el.dom.parentNode;
16513             this.allowDomMove = false;
16514         }
16515         this.container = Roo.get(container);
16516         this.rendered = true;
16517         if(position !== undefined){
16518             if(typeof position == 'number'){
16519                 position = this.container.dom.childNodes[position];
16520             }else{
16521                 position = Roo.getDom(position);
16522             }
16523         }
16524         this.onRender(this.container, position || null);
16525         if(this.cls){
16526             this.el.addClass(this.cls);
16527             delete this.cls;
16528         }
16529         if(this.style){
16530             this.el.applyStyles(this.style);
16531             delete this.style;
16532         }
16533         this.fireEvent("render", this);
16534         this.afterRender(this.container);
16535         if(this.hidden){
16536             this.hide();
16537         }
16538         if(this.disabled){
16539             this.disable();
16540         }
16541
16542         return this;
16543         
16544     },
16545
16546     /** @private */
16547     // default function is not really useful
16548     onRender : function(ct, position){
16549         if(this.el){
16550             this.el = Roo.get(this.el);
16551             if(this.allowDomMove !== false){
16552                 ct.dom.insertBefore(this.el.dom, position);
16553             }
16554         }
16555     },
16556
16557     /** @private */
16558     getAutoCreate : function(){
16559         var cfg = typeof this.autoCreate == "object" ?
16560                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
16561         if(this.id && !cfg.id){
16562             cfg.id = this.id;
16563         }
16564         return cfg;
16565     },
16566
16567     /** @private */
16568     afterRender : Roo.emptyFn,
16569
16570     /**
16571      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
16572      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
16573      */
16574     destroy : function(){
16575         if(this.fireEvent("beforedestroy", this) !== false){
16576             this.purgeListeners();
16577             this.beforeDestroy();
16578             if(this.rendered){
16579                 this.el.removeAllListeners();
16580                 this.el.remove();
16581                 if(this.actionMode == "container"){
16582                     this.container.remove();
16583                 }
16584             }
16585             this.onDestroy();
16586             Roo.ComponentMgr.unregister(this);
16587             this.fireEvent("destroy", this);
16588         }
16589     },
16590
16591         /** @private */
16592     beforeDestroy : function(){
16593
16594     },
16595
16596         /** @private */
16597         onDestroy : function(){
16598
16599     },
16600
16601     /**
16602      * Returns the underlying {@link Roo.Element}.
16603      * @return {Roo.Element} The element
16604      */
16605     getEl : function(){
16606         return this.el;
16607     },
16608
16609     /**
16610      * Returns the id of this component.
16611      * @return {String}
16612      */
16613     getId : function(){
16614         return this.id;
16615     },
16616
16617     /**
16618      * Try to focus this component.
16619      * @param {Boolean} selectText True to also select the text in this component (if applicable)
16620      * @return {Roo.Component} this
16621      */
16622     focus : function(selectText){
16623         if(this.rendered){
16624             this.el.focus();
16625             if(selectText === true){
16626                 this.el.dom.select();
16627             }
16628         }
16629         return this;
16630     },
16631
16632     /** @private */
16633     blur : function(){
16634         if(this.rendered){
16635             this.el.blur();
16636         }
16637         return this;
16638     },
16639
16640     /**
16641      * Disable this component.
16642      * @return {Roo.Component} this
16643      */
16644     disable : function(){
16645         if(this.rendered){
16646             this.onDisable();
16647         }
16648         this.disabled = true;
16649         this.fireEvent("disable", this);
16650         return this;
16651     },
16652
16653         // private
16654     onDisable : function(){
16655         this.getActionEl().addClass(this.disabledClass);
16656         this.el.dom.disabled = true;
16657     },
16658
16659     /**
16660      * Enable this component.
16661      * @return {Roo.Component} this
16662      */
16663     enable : function(){
16664         if(this.rendered){
16665             this.onEnable();
16666         }
16667         this.disabled = false;
16668         this.fireEvent("enable", this);
16669         return this;
16670     },
16671
16672         // private
16673     onEnable : function(){
16674         this.getActionEl().removeClass(this.disabledClass);
16675         this.el.dom.disabled = false;
16676     },
16677
16678     /**
16679      * Convenience function for setting disabled/enabled by boolean.
16680      * @param {Boolean} disabled
16681      */
16682     setDisabled : function(disabled){
16683         this[disabled ? "disable" : "enable"]();
16684     },
16685
16686     /**
16687      * Show this component.
16688      * @return {Roo.Component} this
16689      */
16690     show: function(){
16691         if(this.fireEvent("beforeshow", this) !== false){
16692             this.hidden = false;
16693             if(this.rendered){
16694                 this.onShow();
16695             }
16696             this.fireEvent("show", this);
16697         }
16698         return this;
16699     },
16700
16701     // private
16702     onShow : function(){
16703         var ae = this.getActionEl();
16704         if(this.hideMode == 'visibility'){
16705             ae.dom.style.visibility = "visible";
16706         }else if(this.hideMode == 'offsets'){
16707             ae.removeClass('x-hidden');
16708         }else{
16709             ae.dom.style.display = "";
16710         }
16711     },
16712
16713     /**
16714      * Hide this component.
16715      * @return {Roo.Component} this
16716      */
16717     hide: function(){
16718         if(this.fireEvent("beforehide", this) !== false){
16719             this.hidden = true;
16720             if(this.rendered){
16721                 this.onHide();
16722             }
16723             this.fireEvent("hide", this);
16724         }
16725         return this;
16726     },
16727
16728     // private
16729     onHide : function(){
16730         var ae = this.getActionEl();
16731         if(this.hideMode == 'visibility'){
16732             ae.dom.style.visibility = "hidden";
16733         }else if(this.hideMode == 'offsets'){
16734             ae.addClass('x-hidden');
16735         }else{
16736             ae.dom.style.display = "none";
16737         }
16738     },
16739
16740     /**
16741      * Convenience function to hide or show this component by boolean.
16742      * @param {Boolean} visible True to show, false to hide
16743      * @return {Roo.Component} this
16744      */
16745     setVisible: function(visible){
16746         if(visible) {
16747             this.show();
16748         }else{
16749             this.hide();
16750         }
16751         return this;
16752     },
16753
16754     /**
16755      * Returns true if this component is visible.
16756      */
16757     isVisible : function(){
16758         return this.getActionEl().isVisible();
16759     },
16760
16761     cloneConfig : function(overrides){
16762         overrides = overrides || {};
16763         var id = overrides.id || Roo.id();
16764         var cfg = Roo.applyIf(overrides, this.initialConfig);
16765         cfg.id = id; // prevent dup id
16766         return new this.constructor(cfg);
16767     }
16768 });/*
16769  * Based on:
16770  * Ext JS Library 1.1.1
16771  * Copyright(c) 2006-2007, Ext JS, LLC.
16772  *
16773  * Originally Released Under LGPL - original licence link has changed is not relivant.
16774  *
16775  * Fork - LGPL
16776  * <script type="text/javascript">
16777  */
16778
16779 /**
16780  * @class Roo.BoxComponent
16781  * @extends Roo.Component
16782  * Base class for any visual {@link Roo.Component} that uses a box container.  BoxComponent provides automatic box
16783  * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model.  All
16784  * container classes should subclass BoxComponent so that they will work consistently when nested within other Roo
16785  * layout containers.
16786  * @constructor
16787  * @param {Roo.Element/String/Object} config The configuration options.
16788  */
16789 Roo.BoxComponent = function(config){
16790     Roo.Component.call(this, config);
16791     this.addEvents({
16792         /**
16793          * @event resize
16794          * Fires after the component is resized.
16795              * @param {Roo.Component} this
16796              * @param {Number} adjWidth The box-adjusted width that was set
16797              * @param {Number} adjHeight The box-adjusted height that was set
16798              * @param {Number} rawWidth The width that was originally specified
16799              * @param {Number} rawHeight The height that was originally specified
16800              */
16801         resize : true,
16802         /**
16803          * @event move
16804          * Fires after the component is moved.
16805              * @param {Roo.Component} this
16806              * @param {Number} x The new x position
16807              * @param {Number} y The new y position
16808              */
16809         move : true
16810     });
16811 };
16812
16813 Roo.extend(Roo.BoxComponent, Roo.Component, {
16814     // private, set in afterRender to signify that the component has been rendered
16815     boxReady : false,
16816     // private, used to defer height settings to subclasses
16817     deferHeight: false,
16818     /** @cfg {Number} width
16819      * width (optional) size of component
16820      */
16821      /** @cfg {Number} height
16822      * height (optional) size of component
16823      */
16824      
16825     /**
16826      * Sets the width and height of the component.  This method fires the resize event.  This method can accept
16827      * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
16828      * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
16829      * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
16830      * @return {Roo.BoxComponent} this
16831      */
16832     setSize : function(w, h){
16833         // support for standard size objects
16834         if(typeof w == 'object'){
16835             h = w.height;
16836             w = w.width;
16837         }
16838         // not rendered
16839         if(!this.boxReady){
16840             this.width = w;
16841             this.height = h;
16842             return this;
16843         }
16844
16845         // prevent recalcs when not needed
16846         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
16847             return this;
16848         }
16849         this.lastSize = {width: w, height: h};
16850
16851         var adj = this.adjustSize(w, h);
16852         var aw = adj.width, ah = adj.height;
16853         if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
16854             var rz = this.getResizeEl();
16855             if(!this.deferHeight && aw !== undefined && ah !== undefined){
16856                 rz.setSize(aw, ah);
16857             }else if(!this.deferHeight && ah !== undefined){
16858                 rz.setHeight(ah);
16859             }else if(aw !== undefined){
16860                 rz.setWidth(aw);
16861             }
16862             this.onResize(aw, ah, w, h);
16863             this.fireEvent('resize', this, aw, ah, w, h);
16864         }
16865         return this;
16866     },
16867
16868     /**
16869      * Gets the current size of the component's underlying element.
16870      * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
16871      */
16872     getSize : function(){
16873         return this.el.getSize();
16874     },
16875
16876     /**
16877      * Gets the current XY position of the component's underlying element.
16878      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
16879      * @return {Array} The XY position of the element (e.g., [100, 200])
16880      */
16881     getPosition : function(local){
16882         if(local === true){
16883             return [this.el.getLeft(true), this.el.getTop(true)];
16884         }
16885         return this.xy || this.el.getXY();
16886     },
16887
16888     /**
16889      * Gets the current box measurements of the component's underlying element.
16890      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
16891      * @returns {Object} box An object in the format {x, y, width, height}
16892      */
16893     getBox : function(local){
16894         var s = this.el.getSize();
16895         if(local){
16896             s.x = this.el.getLeft(true);
16897             s.y = this.el.getTop(true);
16898         }else{
16899             var xy = this.xy || this.el.getXY();
16900             s.x = xy[0];
16901             s.y = xy[1];
16902         }
16903         return s;
16904     },
16905
16906     /**
16907      * Sets the current box measurements of the component's underlying element.
16908      * @param {Object} box An object in the format {x, y, width, height}
16909      * @returns {Roo.BoxComponent} this
16910      */
16911     updateBox : function(box){
16912         this.setSize(box.width, box.height);
16913         this.setPagePosition(box.x, box.y);
16914         return this;
16915     },
16916
16917     // protected
16918     getResizeEl : function(){
16919         return this.resizeEl || this.el;
16920     },
16921
16922     // protected
16923     getPositionEl : function(){
16924         return this.positionEl || this.el;
16925     },
16926
16927     /**
16928      * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
16929      * This method fires the move event.
16930      * @param {Number} left The new left
16931      * @param {Number} top The new top
16932      * @returns {Roo.BoxComponent} this
16933      */
16934     setPosition : function(x, y){
16935         this.x = x;
16936         this.y = y;
16937         if(!this.boxReady){
16938             return this;
16939         }
16940         var adj = this.adjustPosition(x, y);
16941         var ax = adj.x, ay = adj.y;
16942
16943         var el = this.getPositionEl();
16944         if(ax !== undefined || ay !== undefined){
16945             if(ax !== undefined && ay !== undefined){
16946                 el.setLeftTop(ax, ay);
16947             }else if(ax !== undefined){
16948                 el.setLeft(ax);
16949             }else if(ay !== undefined){
16950                 el.setTop(ay);
16951             }
16952             this.onPosition(ax, ay);
16953             this.fireEvent('move', this, ax, ay);
16954         }
16955         return this;
16956     },
16957
16958     /**
16959      * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
16960      * This method fires the move event.
16961      * @param {Number} x The new x position
16962      * @param {Number} y The new y position
16963      * @returns {Roo.BoxComponent} this
16964      */
16965     setPagePosition : function(x, y){
16966         this.pageX = x;
16967         this.pageY = y;
16968         if(!this.boxReady){
16969             return;
16970         }
16971         if(x === undefined || y === undefined){ // cannot translate undefined points
16972             return;
16973         }
16974         var p = this.el.translatePoints(x, y);
16975         this.setPosition(p.left, p.top);
16976         return this;
16977     },
16978
16979     // private
16980     onRender : function(ct, position){
16981         Roo.BoxComponent.superclass.onRender.call(this, ct, position);
16982         if(this.resizeEl){
16983             this.resizeEl = Roo.get(this.resizeEl);
16984         }
16985         if(this.positionEl){
16986             this.positionEl = Roo.get(this.positionEl);
16987         }
16988     },
16989
16990     // private
16991     afterRender : function(){
16992         Roo.BoxComponent.superclass.afterRender.call(this);
16993         this.boxReady = true;
16994         this.setSize(this.width, this.height);
16995         if(this.x || this.y){
16996             this.setPosition(this.x, this.y);
16997         }
16998         if(this.pageX || this.pageY){
16999             this.setPagePosition(this.pageX, this.pageY);
17000         }
17001     },
17002
17003     /**
17004      * Force the component's size to recalculate based on the underlying element's current height and width.
17005      * @returns {Roo.BoxComponent} this
17006      */
17007     syncSize : function(){
17008         delete this.lastSize;
17009         this.setSize(this.el.getWidth(), this.el.getHeight());
17010         return this;
17011     },
17012
17013     /**
17014      * Called after the component is resized, this method is empty by default but can be implemented by any
17015      * subclass that needs to perform custom logic after a resize occurs.
17016      * @param {Number} adjWidth The box-adjusted width that was set
17017      * @param {Number} adjHeight The box-adjusted height that was set
17018      * @param {Number} rawWidth The width that was originally specified
17019      * @param {Number} rawHeight The height that was originally specified
17020      */
17021     onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
17022
17023     },
17024
17025     /**
17026      * Called after the component is moved, this method is empty by default but can be implemented by any
17027      * subclass that needs to perform custom logic after a move occurs.
17028      * @param {Number} x The new x position
17029      * @param {Number} y The new y position
17030      */
17031     onPosition : function(x, y){
17032
17033     },
17034
17035     // private
17036     adjustSize : function(w, h){
17037         if(this.autoWidth){
17038             w = 'auto';
17039         }
17040         if(this.autoHeight){
17041             h = 'auto';
17042         }
17043         return {width : w, height: h};
17044     },
17045
17046     // private
17047     adjustPosition : function(x, y){
17048         return {x : x, y: y};
17049     }
17050 });/*
17051  * Based on:
17052  * Ext JS Library 1.1.1
17053  * Copyright(c) 2006-2007, Ext JS, LLC.
17054  *
17055  * Originally Released Under LGPL - original licence link has changed is not relivant.
17056  *
17057  * Fork - LGPL
17058  * <script type="text/javascript">
17059  */
17060  (function(){ 
17061 /**
17062  * @class Roo.Layer
17063  * @extends Roo.Element
17064  * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
17065  * automatic maintaining of shadow/shim positions.
17066  * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
17067  * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
17068  * you can pass a string with a CSS class name. False turns off the shadow.
17069  * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
17070  * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
17071  * @cfg {String} cls CSS class to add to the element
17072  * @cfg {Number} zindex Starting z-index (defaults to 11000)
17073  * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
17074  * @constructor
17075  * @param {Object} config An object with config options.
17076  * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
17077  */
17078
17079 Roo.Layer = function(config, existingEl){
17080     config = config || {};
17081     var dh = Roo.DomHelper;
17082     var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
17083     if(existingEl){
17084         this.dom = Roo.getDom(existingEl);
17085     }
17086     if(!this.dom){
17087         var o = config.dh || {tag: "div", cls: "x-layer"};
17088         this.dom = dh.append(pel, o);
17089     }
17090     if(config.cls){
17091         this.addClass(config.cls);
17092     }
17093     this.constrain = config.constrain !== false;
17094     this.visibilityMode = Roo.Element.VISIBILITY;
17095     if(config.id){
17096         this.id = this.dom.id = config.id;
17097     }else{
17098         this.id = Roo.id(this.dom);
17099     }
17100     this.zindex = config.zindex || this.getZIndex();
17101     this.position("absolute", this.zindex);
17102     if(config.shadow){
17103         this.shadowOffset = config.shadowOffset || 4;
17104         this.shadow = new Roo.Shadow({
17105             offset : this.shadowOffset,
17106             mode : config.shadow
17107         });
17108     }else{
17109         this.shadowOffset = 0;
17110     }
17111     this.useShim = config.shim !== false && Roo.useShims;
17112     this.useDisplay = config.useDisplay;
17113     this.hide();
17114 };
17115
17116 var supr = Roo.Element.prototype;
17117
17118 // shims are shared among layer to keep from having 100 iframes
17119 var shims = [];
17120
17121 Roo.extend(Roo.Layer, Roo.Element, {
17122
17123     getZIndex : function(){
17124         return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
17125     },
17126
17127     getShim : function(){
17128         if(!this.useShim){
17129             return null;
17130         }
17131         if(this.shim){
17132             return this.shim;
17133         }
17134         var shim = shims.shift();
17135         if(!shim){
17136             shim = this.createShim();
17137             shim.enableDisplayMode('block');
17138             shim.dom.style.display = 'none';
17139             shim.dom.style.visibility = 'visible';
17140         }
17141         var pn = this.dom.parentNode;
17142         if(shim.dom.parentNode != pn){
17143             pn.insertBefore(shim.dom, this.dom);
17144         }
17145         shim.setStyle('z-index', this.getZIndex()-2);
17146         this.shim = shim;
17147         return shim;
17148     },
17149
17150     hideShim : function(){
17151         if(this.shim){
17152             this.shim.setDisplayed(false);
17153             shims.push(this.shim);
17154             delete this.shim;
17155         }
17156     },
17157
17158     disableShadow : function(){
17159         if(this.shadow){
17160             this.shadowDisabled = true;
17161             this.shadow.hide();
17162             this.lastShadowOffset = this.shadowOffset;
17163             this.shadowOffset = 0;
17164         }
17165     },
17166
17167     enableShadow : function(show){
17168         if(this.shadow){
17169             this.shadowDisabled = false;
17170             this.shadowOffset = this.lastShadowOffset;
17171             delete this.lastShadowOffset;
17172             if(show){
17173                 this.sync(true);
17174             }
17175         }
17176     },
17177
17178     // private
17179     // this code can execute repeatedly in milliseconds (i.e. during a drag) so
17180     // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
17181     sync : function(doShow){
17182         var sw = this.shadow;
17183         if(!this.updating && this.isVisible() && (sw || this.useShim)){
17184             var sh = this.getShim();
17185
17186             var w = this.getWidth(),
17187                 h = this.getHeight();
17188
17189             var l = this.getLeft(true),
17190                 t = this.getTop(true);
17191
17192             if(sw && !this.shadowDisabled){
17193                 if(doShow && !sw.isVisible()){
17194                     sw.show(this);
17195                 }else{
17196                     sw.realign(l, t, w, h);
17197                 }
17198                 if(sh){
17199                     if(doShow){
17200                        sh.show();
17201                     }
17202                     // fit the shim behind the shadow, so it is shimmed too
17203                     var a = sw.adjusts, s = sh.dom.style;
17204                     s.left = (Math.min(l, l+a.l))+"px";
17205                     s.top = (Math.min(t, t+a.t))+"px";
17206                     s.width = (w+a.w)+"px";
17207                     s.height = (h+a.h)+"px";
17208                 }
17209             }else if(sh){
17210                 if(doShow){
17211                    sh.show();
17212                 }
17213                 sh.setSize(w, h);
17214                 sh.setLeftTop(l, t);
17215             }
17216             
17217         }
17218     },
17219
17220     // private
17221     destroy : function(){
17222         this.hideShim();
17223         if(this.shadow){
17224             this.shadow.hide();
17225         }
17226         this.removeAllListeners();
17227         var pn = this.dom.parentNode;
17228         if(pn){
17229             pn.removeChild(this.dom);
17230         }
17231         Roo.Element.uncache(this.id);
17232     },
17233
17234     remove : function(){
17235         this.destroy();
17236     },
17237
17238     // private
17239     beginUpdate : function(){
17240         this.updating = true;
17241     },
17242
17243     // private
17244     endUpdate : function(){
17245         this.updating = false;
17246         this.sync(true);
17247     },
17248
17249     // private
17250     hideUnders : function(negOffset){
17251         if(this.shadow){
17252             this.shadow.hide();
17253         }
17254         this.hideShim();
17255     },
17256
17257     // private
17258     constrainXY : function(){
17259         if(this.constrain){
17260             var vw = Roo.lib.Dom.getViewWidth(),
17261                 vh = Roo.lib.Dom.getViewHeight();
17262             var s = Roo.get(document).getScroll();
17263
17264             var xy = this.getXY();
17265             var x = xy[0], y = xy[1];   
17266             var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
17267             // only move it if it needs it
17268             var moved = false;
17269             // first validate right/bottom
17270             if((x + w) > vw+s.left){
17271                 x = vw - w - this.shadowOffset;
17272                 moved = true;
17273             }
17274             if((y + h) > vh+s.top){
17275                 y = vh - h - this.shadowOffset;
17276                 moved = true;
17277             }
17278             // then make sure top/left isn't negative
17279             if(x < s.left){
17280                 x = s.left;
17281                 moved = true;
17282             }
17283             if(y < s.top){
17284                 y = s.top;
17285                 moved = true;
17286             }
17287             if(moved){
17288                 if(this.avoidY){
17289                     var ay = this.avoidY;
17290                     if(y <= ay && (y+h) >= ay){
17291                         y = ay-h-5;   
17292                     }
17293                 }
17294                 xy = [x, y];
17295                 this.storeXY(xy);
17296                 supr.setXY.call(this, xy);
17297                 this.sync();
17298             }
17299         }
17300     },
17301
17302     isVisible : function(){
17303         return this.visible;    
17304     },
17305
17306     // private
17307     showAction : function(){
17308         this.visible = true; // track visibility to prevent getStyle calls
17309         if(this.useDisplay === true){
17310             this.setDisplayed("");
17311         }else if(this.lastXY){
17312             supr.setXY.call(this, this.lastXY);
17313         }else if(this.lastLT){
17314             supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
17315         }
17316     },
17317
17318     // private
17319     hideAction : function(){
17320         this.visible = false;
17321         if(this.useDisplay === true){
17322             this.setDisplayed(false);
17323         }else{
17324             this.setLeftTop(-10000,-10000);
17325         }
17326     },
17327
17328     // overridden Element method
17329     setVisible : function(v, a, d, c, e){
17330         if(v){
17331             this.showAction();
17332         }
17333         if(a && v){
17334             var cb = function(){
17335                 this.sync(true);
17336                 if(c){
17337                     c();
17338                 }
17339             }.createDelegate(this);
17340             supr.setVisible.call(this, true, true, d, cb, e);
17341         }else{
17342             if(!v){
17343                 this.hideUnders(true);
17344             }
17345             var cb = c;
17346             if(a){
17347                 cb = function(){
17348                     this.hideAction();
17349                     if(c){
17350                         c();
17351                     }
17352                 }.createDelegate(this);
17353             }
17354             supr.setVisible.call(this, v, a, d, cb, e);
17355             if(v){
17356                 this.sync(true);
17357             }else if(!a){
17358                 this.hideAction();
17359             }
17360         }
17361     },
17362
17363     storeXY : function(xy){
17364         delete this.lastLT;
17365         this.lastXY = xy;
17366     },
17367
17368     storeLeftTop : function(left, top){
17369         delete this.lastXY;
17370         this.lastLT = [left, top];
17371     },
17372
17373     // private
17374     beforeFx : function(){
17375         this.beforeAction();
17376         return Roo.Layer.superclass.beforeFx.apply(this, arguments);
17377     },
17378
17379     // private
17380     afterFx : function(){
17381         Roo.Layer.superclass.afterFx.apply(this, arguments);
17382         this.sync(this.isVisible());
17383     },
17384
17385     // private
17386     beforeAction : function(){
17387         if(!this.updating && this.shadow){
17388             this.shadow.hide();
17389         }
17390     },
17391
17392     // overridden Element method
17393     setLeft : function(left){
17394         this.storeLeftTop(left, this.getTop(true));
17395         supr.setLeft.apply(this, arguments);
17396         this.sync();
17397     },
17398
17399     setTop : function(top){
17400         this.storeLeftTop(this.getLeft(true), top);
17401         supr.setTop.apply(this, arguments);
17402         this.sync();
17403     },
17404
17405     setLeftTop : function(left, top){
17406         this.storeLeftTop(left, top);
17407         supr.setLeftTop.apply(this, arguments);
17408         this.sync();
17409     },
17410
17411     setXY : function(xy, a, d, c, e){
17412         this.fixDisplay();
17413         this.beforeAction();
17414         this.storeXY(xy);
17415         var cb = this.createCB(c);
17416         supr.setXY.call(this, xy, a, d, cb, e);
17417         if(!a){
17418             cb();
17419         }
17420     },
17421
17422     // private
17423     createCB : function(c){
17424         var el = this;
17425         return function(){
17426             el.constrainXY();
17427             el.sync(true);
17428             if(c){
17429                 c();
17430             }
17431         };
17432     },
17433
17434     // overridden Element method
17435     setX : function(x, a, d, c, e){
17436         this.setXY([x, this.getY()], a, d, c, e);
17437     },
17438
17439     // overridden Element method
17440     setY : function(y, a, d, c, e){
17441         this.setXY([this.getX(), y], a, d, c, e);
17442     },
17443
17444     // overridden Element method
17445     setSize : function(w, h, a, d, c, e){
17446         this.beforeAction();
17447         var cb = this.createCB(c);
17448         supr.setSize.call(this, w, h, a, d, cb, e);
17449         if(!a){
17450             cb();
17451         }
17452     },
17453
17454     // overridden Element method
17455     setWidth : function(w, a, d, c, e){
17456         this.beforeAction();
17457         var cb = this.createCB(c);
17458         supr.setWidth.call(this, w, a, d, cb, e);
17459         if(!a){
17460             cb();
17461         }
17462     },
17463
17464     // overridden Element method
17465     setHeight : function(h, a, d, c, e){
17466         this.beforeAction();
17467         var cb = this.createCB(c);
17468         supr.setHeight.call(this, h, a, d, cb, e);
17469         if(!a){
17470             cb();
17471         }
17472     },
17473
17474     // overridden Element method
17475     setBounds : function(x, y, w, h, a, d, c, e){
17476         this.beforeAction();
17477         var cb = this.createCB(c);
17478         if(!a){
17479             this.storeXY([x, y]);
17480             supr.setXY.call(this, [x, y]);
17481             supr.setSize.call(this, w, h, a, d, cb, e);
17482             cb();
17483         }else{
17484             supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
17485         }
17486         return this;
17487     },
17488     
17489     /**
17490      * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
17491      * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
17492      * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
17493      * @param {Number} zindex The new z-index to set
17494      * @return {this} The Layer
17495      */
17496     setZIndex : function(zindex){
17497         this.zindex = zindex;
17498         this.setStyle("z-index", zindex + 2);
17499         if(this.shadow){
17500             this.shadow.setZIndex(zindex + 1);
17501         }
17502         if(this.shim){
17503             this.shim.setStyle("z-index", zindex);
17504         }
17505     }
17506 });
17507 })();/*
17508  * Original code for Roojs - LGPL
17509  * <script type="text/javascript">
17510  */
17511  
17512 /**
17513  * @class Roo.XComponent
17514  * A delayed Element creator...
17515  * Or a way to group chunks of interface together.
17516  * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
17517  *  used in conjunction with XComponent.build() it will create an instance of each element,
17518  *  then call addxtype() to build the User interface.
17519  * 
17520  * Mypart.xyx = new Roo.XComponent({
17521
17522     parent : 'Mypart.xyz', // empty == document.element.!!
17523     order : '001',
17524     name : 'xxxx'
17525     region : 'xxxx'
17526     disabled : function() {} 
17527      
17528     tree : function() { // return an tree of xtype declared components
17529         var MODULE = this;
17530         return 
17531         {
17532             xtype : 'NestedLayoutPanel',
17533             // technicall
17534         }
17535      ]
17536  *})
17537  *
17538  *
17539  * It can be used to build a big heiracy, with parent etc.
17540  * or you can just use this to render a single compoent to a dom element
17541  * MYPART.render(Roo.Element | String(id) | dom_element )
17542  *
17543  *
17544  * Usage patterns.
17545  *
17546  * Classic Roo
17547  *
17548  * Roo is designed primarily as a single page application, so the UI build for a standard interface will
17549  * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
17550  *
17551  * Each sub module is expected to have a parent pointing to the class name of it's parent module.
17552  *
17553  * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
17554  * - if mulitple topModules exist, the last one is defined as the top module.
17555  *
17556  * Embeded Roo
17557  * 
17558  * When the top level or multiple modules are to embedded into a existing HTML page,
17559  * the parent element can container '#id' of the element where the module will be drawn.
17560  *
17561  * Bootstrap Roo
17562  *
17563  * Unlike classic Roo, the bootstrap tends not to be used as a single page.
17564  * it relies more on a include mechanism, where sub modules are included into an outer page.
17565  * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
17566  * 
17567  * Bootstrap Roo Included elements
17568  *
17569  * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
17570  * hence confusing the component builder as it thinks there are multiple top level elements. 
17571  *
17572  * String Over-ride & Translations
17573  *
17574  * Our builder application writes all the strings as _strings and _named_strings. This is to enable the translation of elements,
17575  * and also the 'overlaying of string values - needed when different versions of the same application with different text content
17576  * are needed. @see Roo.XComponent.overlayString  
17577  * 
17578  * 
17579  * 
17580  * @extends Roo.util.Observable
17581  * @constructor
17582  * @param cfg {Object} configuration of component
17583  * 
17584  */
17585 Roo.XComponent = function(cfg) {
17586     Roo.apply(this, cfg);
17587     this.addEvents({ 
17588         /**
17589              * @event built
17590              * Fires when this the componnt is built
17591              * @param {Roo.XComponent} c the component
17592              */
17593         'built' : true
17594         
17595     });
17596     this.region = this.region || 'center'; // default..
17597     Roo.XComponent.register(this);
17598     this.modules = false;
17599     this.el = false; // where the layout goes..
17600     
17601     
17602 }
17603 Roo.extend(Roo.XComponent, Roo.util.Observable, {
17604     /**
17605      * @property el
17606      * The created element (with Roo.factory())
17607      * @type {Roo.Layout}
17608      */
17609     el  : false,
17610     
17611     /**
17612      * @property el
17613      * for BC  - use el in new code
17614      * @type {Roo.Layout}
17615      */
17616     panel : false,
17617     
17618     /**
17619      * @property layout
17620      * for BC  - use el in new code
17621      * @type {Roo.Layout}
17622      */
17623     layout : false,
17624     
17625      /**
17626      * @cfg {Function|boolean} disabled
17627      * If this module is disabled by some rule, return true from the funtion
17628      */
17629     disabled : false,
17630     
17631     /**
17632      * @cfg {String} parent 
17633      * Name of parent element which it get xtype added to..
17634      */
17635     parent: false,
17636     
17637     /**
17638      * @cfg {String} order
17639      * Used to set the order in which elements are created (usefull for multiple tabs)
17640      */
17641     
17642     order : false,
17643     /**
17644      * @cfg {String} name
17645      * String to display while loading.
17646      */
17647     name : false,
17648     /**
17649      * @cfg {String} region
17650      * Region to render component to (defaults to center)
17651      */
17652     region : 'center',
17653     
17654     /**
17655      * @cfg {Array} items
17656      * A single item array - the first element is the root of the tree..
17657      * It's done this way to stay compatible with the Xtype system...
17658      */
17659     items : false,
17660     
17661     /**
17662      * @property _tree
17663      * The method that retuns the tree of parts that make up this compoennt 
17664      * @type {function}
17665      */
17666     _tree  : false,
17667     
17668      /**
17669      * render
17670      * render element to dom or tree
17671      * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
17672      */
17673     
17674     render : function(el)
17675     {
17676         
17677         el = el || false;
17678         var hp = this.parent ? 1 : 0;
17679         Roo.debug &&  Roo.log(this);
17680         
17681         var tree = this._tree ? this._tree() : this.tree();
17682
17683         
17684         if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
17685             // if parent is a '#.....' string, then let's use that..
17686             var ename = this.parent.substr(1);
17687             this.parent = false;
17688             Roo.debug && Roo.log(ename);
17689             switch (ename) {
17690                 case 'bootstrap-body':
17691                     if (typeof(tree.el) != 'undefined' && tree.el == document.body)  {
17692                         // this is the BorderLayout standard?
17693                        this.parent = { el : true };
17694                        break;
17695                     }
17696                     if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype)  > -1)  {
17697                         // need to insert stuff...
17698                         this.parent =  {
17699                              el : new Roo.bootstrap.layout.Border({
17700                                  el : document.body, 
17701                      
17702                                  center: {
17703                                     titlebar: false,
17704                                     autoScroll:false,
17705                                     closeOnTab: true,
17706                                     tabPosition: 'top',
17707                                       //resizeTabs: true,
17708                                     alwaysShowTabs: true,
17709                                     hideTabs: false
17710                                      //minTabWidth: 140
17711                                  }
17712                              })
17713                         
17714                          };
17715                          break;
17716                     }
17717                          
17718                     if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
17719                         this.parent = { el :  new  Roo.bootstrap.Body() };
17720                         Roo.debug && Roo.log("setting el to doc body");
17721                          
17722                     } else {
17723                         throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
17724                     }
17725                     break;
17726                 case 'bootstrap':
17727                     this.parent = { el : true};
17728                     // fall through
17729                 default:
17730                     el = Roo.get(ename);
17731                     if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
17732                         this.parent = { el : true};
17733                     }
17734                     
17735                     break;
17736             }
17737                 
17738             
17739             if (!el && !this.parent) {
17740                 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
17741                 return;
17742             }
17743         }
17744         
17745         Roo.debug && Roo.log("EL:");
17746         Roo.debug && Roo.log(el);
17747         Roo.debug && Roo.log("this.parent.el:");
17748         Roo.debug && Roo.log(this.parent.el);
17749         
17750
17751         // altertive root elements ??? - we need a better way to indicate these.
17752         var is_alt = Roo.XComponent.is_alt ||
17753                     (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
17754                     (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
17755                     (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
17756         
17757         
17758         
17759         if (!this.parent && is_alt) {
17760             //el = Roo.get(document.body);
17761             this.parent = { el : true };
17762         }
17763             
17764             
17765         
17766         if (!this.parent) {
17767             
17768             Roo.debug && Roo.log("no parent - creating one");
17769             
17770             el = el ? Roo.get(el) : false;      
17771             
17772             if (typeof(Roo.BorderLayout) == 'undefined' ) {
17773                 
17774                 this.parent =  {
17775                     el : new Roo.bootstrap.layout.Border({
17776                         el: el || document.body,
17777                     
17778                         center: {
17779                             titlebar: false,
17780                             autoScroll:false,
17781                             closeOnTab: true,
17782                             tabPosition: 'top',
17783                              //resizeTabs: true,
17784                             alwaysShowTabs: false,
17785                             hideTabs: true,
17786                             minTabWidth: 140,
17787                             overflow: 'visible'
17788                          }
17789                      })
17790                 };
17791             } else {
17792             
17793                 // it's a top level one..
17794                 this.parent =  {
17795                     el : new Roo.BorderLayout(el || document.body, {
17796                         center: {
17797                             titlebar: false,
17798                             autoScroll:false,
17799                             closeOnTab: true,
17800                             tabPosition: 'top',
17801                              //resizeTabs: true,
17802                             alwaysShowTabs: el && hp? false :  true,
17803                             hideTabs: el || !hp ? true :  false,
17804                             minTabWidth: 140
17805                          }
17806                     })
17807                 };
17808             }
17809         }
17810         
17811         if (!this.parent.el) {
17812                 // probably an old style ctor, which has been disabled.
17813                 return;
17814
17815         }
17816                 // The 'tree' method is  '_tree now' 
17817             
17818         tree.region = tree.region || this.region;
17819         var is_body = false;
17820         if (this.parent.el === true) {
17821             // bootstrap... - body..
17822             if (el) {
17823                 tree.el = el;
17824             }
17825             this.parent.el = Roo.factory(tree);
17826             is_body = true;
17827         }
17828         
17829         this.el = this.parent.el.addxtype(tree, undefined, is_body);
17830         this.fireEvent('built', this);
17831         
17832         this.panel = this.el;
17833         this.layout = this.panel.layout;
17834         this.parentLayout = this.parent.layout  || false;  
17835          
17836     }
17837     
17838 });
17839
17840 Roo.apply(Roo.XComponent, {
17841     /**
17842      * @property  hideProgress
17843      * true to disable the building progress bar.. usefull on single page renders.
17844      * @type Boolean
17845      */
17846     hideProgress : false,
17847     /**
17848      * @property  buildCompleted
17849      * True when the builder has completed building the interface.
17850      * @type Boolean
17851      */
17852     buildCompleted : false,
17853      
17854     /**
17855      * @property  topModule
17856      * the upper most module - uses document.element as it's constructor.
17857      * @type Object
17858      */
17859      
17860     topModule  : false,
17861       
17862     /**
17863      * @property  modules
17864      * array of modules to be created by registration system.
17865      * @type {Array} of Roo.XComponent
17866      */
17867     
17868     modules : [],
17869     /**
17870      * @property  elmodules
17871      * array of modules to be created by which use #ID 
17872      * @type {Array} of Roo.XComponent
17873      */
17874      
17875     elmodules : [],
17876
17877      /**
17878      * @property  is_alt
17879      * Is an alternative Root - normally used by bootstrap or other systems,
17880      *    where the top element in the tree can wrap 'body' 
17881      * @type {boolean}  (default false)
17882      */
17883      
17884     is_alt : false,
17885     /**
17886      * @property  build_from_html
17887      * Build elements from html - used by bootstrap HTML stuff 
17888      *    - this is cleared after build is completed
17889      * @type {boolean}    (default false)
17890      */
17891      
17892     build_from_html : false,
17893     /**
17894      * Register components to be built later.
17895      *
17896      * This solves the following issues
17897      * - Building is not done on page load, but after an authentication process has occured.
17898      * - Interface elements are registered on page load
17899      * - Parent Interface elements may not be loaded before child, so this handles that..
17900      * 
17901      *
17902      * example:
17903      * 
17904      * MyApp.register({
17905           order : '000001',
17906           module : 'Pman.Tab.projectMgr',
17907           region : 'center',
17908           parent : 'Pman.layout',
17909           disabled : false,  // or use a function..
17910         })
17911      
17912      * * @param {Object} details about module
17913      */
17914     register : function(obj) {
17915                 
17916         Roo.XComponent.event.fireEvent('register', obj);
17917         switch(typeof(obj.disabled) ) {
17918                 
17919             case 'undefined':
17920                 break;
17921             
17922             case 'function':
17923                 if ( obj.disabled() ) {
17924                         return;
17925                 }
17926                 break;
17927             
17928             default:
17929                 if (obj.disabled || obj.region == '#disabled') {
17930                         return;
17931                 }
17932                 break;
17933         }
17934                 
17935         this.modules.push(obj);
17936          
17937     },
17938     /**
17939      * convert a string to an object..
17940      * eg. 'AAA.BBB' -> finds AAA.BBB
17941
17942      */
17943     
17944     toObject : function(str)
17945     {
17946         if (!str || typeof(str) == 'object') {
17947             return str;
17948         }
17949         if (str.substring(0,1) == '#') {
17950             return str;
17951         }
17952
17953         var ar = str.split('.');
17954         var rt, o;
17955         rt = ar.shift();
17956             /** eval:var:o */
17957         try {
17958             eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
17959         } catch (e) {
17960             throw "Module not found : " + str;
17961         }
17962         
17963         if (o === false) {
17964             throw "Module not found : " + str;
17965         }
17966         Roo.each(ar, function(e) {
17967             if (typeof(o[e]) == 'undefined') {
17968                 throw "Module not found : " + str;
17969             }
17970             o = o[e];
17971         });
17972         
17973         return o;
17974         
17975     },
17976     
17977     
17978     /**
17979      * move modules into their correct place in the tree..
17980      * 
17981      */
17982     preBuild : function ()
17983     {
17984         var _t = this;
17985         Roo.each(this.modules , function (obj)
17986         {
17987             Roo.XComponent.event.fireEvent('beforebuild', obj);
17988             
17989             var opar = obj.parent;
17990             try { 
17991                 obj.parent = this.toObject(opar);
17992             } catch(e) {
17993                 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
17994                 return;
17995             }
17996             
17997             if (!obj.parent) {
17998                 Roo.debug && Roo.log("GOT top level module");
17999                 Roo.debug && Roo.log(obj);
18000                 obj.modules = new Roo.util.MixedCollection(false, 
18001                     function(o) { return o.order + '' }
18002                 );
18003                 this.topModule = obj;
18004                 return;
18005             }
18006                         // parent is a string (usually a dom element name..)
18007             if (typeof(obj.parent) == 'string') {
18008                 this.elmodules.push(obj);
18009                 return;
18010             }
18011             if (obj.parent.constructor != Roo.XComponent) {
18012                 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
18013             }
18014             if (!obj.parent.modules) {
18015                 obj.parent.modules = new Roo.util.MixedCollection(false, 
18016                     function(o) { return o.order + '' }
18017                 );
18018             }
18019             if (obj.parent.disabled) {
18020                 obj.disabled = true;
18021             }
18022             obj.parent.modules.add(obj);
18023         }, this);
18024     },
18025     
18026      /**
18027      * make a list of modules to build.
18028      * @return {Array} list of modules. 
18029      */ 
18030     
18031     buildOrder : function()
18032     {
18033         var _this = this;
18034         var cmp = function(a,b) {   
18035             return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
18036         };
18037         if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
18038             throw "No top level modules to build";
18039         }
18040         
18041         // make a flat list in order of modules to build.
18042         var mods = this.topModule ? [ this.topModule ] : [];
18043                 
18044         
18045         // elmodules (is a list of DOM based modules )
18046         Roo.each(this.elmodules, function(e) {
18047             mods.push(e);
18048             if (!this.topModule &&
18049                 typeof(e.parent) == 'string' &&
18050                 e.parent.substring(0,1) == '#' &&
18051                 Roo.get(e.parent.substr(1))
18052                ) {
18053                 
18054                 _this.topModule = e;
18055             }
18056             
18057         });
18058
18059         
18060         // add modules to their parents..
18061         var addMod = function(m) {
18062             Roo.debug && Roo.log("build Order: add: " + m.name);
18063                 
18064             mods.push(m);
18065             if (m.modules && !m.disabled) {
18066                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
18067                 m.modules.keySort('ASC',  cmp );
18068                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
18069     
18070                 m.modules.each(addMod);
18071             } else {
18072                 Roo.debug && Roo.log("build Order: no child modules");
18073             }
18074             // not sure if this is used any more..
18075             if (m.finalize) {
18076                 m.finalize.name = m.name + " (clean up) ";
18077                 mods.push(m.finalize);
18078             }
18079             
18080         }
18081         if (this.topModule && this.topModule.modules) { 
18082             this.topModule.modules.keySort('ASC',  cmp );
18083             this.topModule.modules.each(addMod);
18084         } 
18085         return mods;
18086     },
18087     
18088      /**
18089      * Build the registered modules.
18090      * @param {Object} parent element.
18091      * @param {Function} optional method to call after module has been added.
18092      * 
18093      */ 
18094    
18095     build : function(opts) 
18096     {
18097         
18098         if (typeof(opts) != 'undefined') {
18099             Roo.apply(this,opts);
18100         }
18101         
18102         this.preBuild();
18103         var mods = this.buildOrder();
18104       
18105         //this.allmods = mods;
18106         //Roo.debug && Roo.log(mods);
18107         //return;
18108         if (!mods.length) { // should not happen
18109             throw "NO modules!!!";
18110         }
18111         
18112         
18113         var msg = "Building Interface...";
18114         // flash it up as modal - so we store the mask!?
18115         if (!this.hideProgress && Roo.MessageBox) {
18116             Roo.MessageBox.show({ title: 'loading' });
18117             Roo.MessageBox.show({
18118                title: "Please wait...",
18119                msg: msg,
18120                width:450,
18121                progress:true,
18122                buttons : false,
18123                closable:false,
18124                modal: false
18125               
18126             });
18127         }
18128         var total = mods.length;
18129         
18130         var _this = this;
18131         var progressRun = function() {
18132             if (!mods.length) {
18133                 Roo.debug && Roo.log('hide?');
18134                 if (!this.hideProgress && Roo.MessageBox) {
18135                     Roo.MessageBox.hide();
18136                 }
18137                 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
18138                 
18139                 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
18140                 
18141                 // THE END...
18142                 return false;   
18143             }
18144             
18145             var m = mods.shift();
18146             
18147             
18148             Roo.debug && Roo.log(m);
18149             // not sure if this is supported any more.. - modules that are are just function
18150             if (typeof(m) == 'function') { 
18151                 m.call(this);
18152                 return progressRun.defer(10, _this);
18153             } 
18154             
18155             
18156             msg = "Building Interface " + (total  - mods.length) + 
18157                     " of " + total + 
18158                     (m.name ? (' - ' + m.name) : '');
18159                         Roo.debug && Roo.log(msg);
18160             if (!_this.hideProgress &&  Roo.MessageBox) { 
18161                 Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
18162             }
18163             
18164          
18165             // is the module disabled?
18166             var disabled = (typeof(m.disabled) == 'function') ?
18167                 m.disabled.call(m.module.disabled) : m.disabled;    
18168             
18169             
18170             if (disabled) {
18171                 return progressRun(); // we do not update the display!
18172             }
18173             
18174             // now build 
18175             
18176                         
18177                         
18178             m.render();
18179             // it's 10 on top level, and 1 on others??? why...
18180             return progressRun.defer(10, _this);
18181              
18182         }
18183         progressRun.defer(1, _this);
18184      
18185         
18186         
18187     },
18188     /**
18189      * Overlay a set of modified strings onto a component
18190      * This is dependant on our builder exporting the strings and 'named strings' elements.
18191      * 
18192      * @param {Object} element to overlay on - eg. Pman.Dialog.Login
18193      * @param {Object} associative array of 'named' string and it's new value.
18194      * 
18195      */
18196         overlayStrings : function( component, strings )
18197     {
18198         if (typeof(component['_named_strings']) == 'undefined') {
18199             throw "ERROR: component does not have _named_strings";
18200         }
18201         for ( var k in strings ) {
18202             var md = typeof(component['_named_strings'][k]) == 'undefined' ? false : component['_named_strings'][k];
18203             if (md !== false) {
18204                 component['_strings'][md] = strings[k];
18205             } else {
18206                 Roo.log('could not find named string: ' + k + ' in');
18207                 Roo.log(component);
18208             }
18209             
18210         }
18211         
18212     },
18213     
18214         
18215         /**
18216          * Event Object.
18217          *
18218          *
18219          */
18220         event: false, 
18221     /**
18222          * wrapper for event.on - aliased later..  
18223          * Typically use to register a event handler for register:
18224          *
18225          * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
18226          *
18227          */
18228     on : false
18229    
18230     
18231     
18232 });
18233
18234 Roo.XComponent.event = new Roo.util.Observable({
18235                 events : { 
18236                         /**
18237                          * @event register
18238                          * Fires when an Component is registered,
18239                          * set the disable property on the Component to stop registration.
18240                          * @param {Roo.XComponent} c the component being registerd.
18241                          * 
18242                          */
18243                         'register' : true,
18244             /**
18245                          * @event beforebuild
18246                          * Fires before each Component is built
18247                          * can be used to apply permissions.
18248                          * @param {Roo.XComponent} c the component being registerd.
18249                          * 
18250                          */
18251                         'beforebuild' : true,
18252                         /**
18253                          * @event buildcomplete
18254                          * Fires on the top level element when all elements have been built
18255                          * @param {Roo.XComponent} the top level component.
18256                          */
18257                         'buildcomplete' : true
18258                         
18259                 }
18260 });
18261
18262 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event); 
18263  //
18264  /**
18265  * marked - a markdown parser
18266  * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
18267  * https://github.com/chjj/marked
18268  */
18269
18270
18271 /**
18272  *
18273  * Roo.Markdown - is a very crude wrapper around marked..
18274  *
18275  * usage:
18276  * 
18277  * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
18278  * 
18279  * Note: move the sample code to the bottom of this
18280  * file before uncommenting it.
18281  *
18282  */
18283
18284 Roo.Markdown = {};
18285 Roo.Markdown.toHtml = function(text) {
18286     
18287     var c = new Roo.Markdown.marked.setOptions({
18288             renderer: new Roo.Markdown.marked.Renderer(),
18289             gfm: true,
18290             tables: true,
18291             breaks: false,
18292             pedantic: false,
18293             sanitize: false,
18294             smartLists: true,
18295             smartypants: false
18296           });
18297     // A FEW HACKS!!?
18298     
18299     text = text.replace(/\\\n/g,' ');
18300     return Roo.Markdown.marked(text);
18301 };
18302 //
18303 // converter
18304 //
18305 // Wraps all "globals" so that the only thing
18306 // exposed is makeHtml().
18307 //
18308 (function() {
18309     
18310      /**
18311          * eval:var:escape
18312          * eval:var:unescape
18313          * eval:var:replace
18314          */
18315       
18316     /**
18317      * Helpers
18318      */
18319     
18320     var escape = function (html, encode) {
18321       return html
18322         .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&amp;')
18323         .replace(/</g, '&lt;')
18324         .replace(/>/g, '&gt;')
18325         .replace(/"/g, '&quot;')
18326         .replace(/'/g, '&#39;');
18327     }
18328     
18329     var unescape = function (html) {
18330         // explicitly match decimal, hex, and named HTML entities 
18331       return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
18332         n = n.toLowerCase();
18333         if (n === 'colon') { return ':'; }
18334         if (n.charAt(0) === '#') {
18335           return n.charAt(1) === 'x'
18336             ? String.fromCharCode(parseInt(n.substring(2), 16))
18337             : String.fromCharCode(+n.substring(1));
18338         }
18339         return '';
18340       });
18341     }
18342     
18343     var replace = function (regex, opt) {
18344       regex = regex.source;
18345       opt = opt || '';
18346       return function self(name, val) {
18347         if (!name) { return new RegExp(regex, opt); }
18348         val = val.source || val;
18349         val = val.replace(/(^|[^\[])\^/g, '$1');
18350         regex = regex.replace(name, val);
18351         return self;
18352       };
18353     }
18354
18355
18356          /**
18357          * eval:var:noop
18358     */
18359     var noop = function () {}
18360     noop.exec = noop;
18361     
18362          /**
18363          * eval:var:merge
18364     */
18365     var merge = function (obj) {
18366       var i = 1
18367         , target
18368         , key;
18369     
18370       for (; i < arguments.length; i++) {
18371         target = arguments[i];
18372         for (key in target) {
18373           if (Object.prototype.hasOwnProperty.call(target, key)) {
18374             obj[key] = target[key];
18375           }
18376         }
18377       }
18378     
18379       return obj;
18380     }
18381     
18382     
18383     /**
18384      * Block-Level Grammar
18385      */
18386     
18387     
18388     
18389     
18390     var block = {
18391       newline: /^\n+/,
18392       code: /^( {4}[^\n]+\n*)+/,
18393       fences: noop,
18394       hr: /^( *[-*_]){3,} *(?:\n+|$)/,
18395       heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
18396       nptable: noop,
18397       lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
18398       blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
18399       list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
18400       html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
18401       def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
18402       table: noop,
18403       paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
18404       text: /^[^\n]+/
18405     };
18406     
18407     block.bullet = /(?:[*+-]|\d+\.)/;
18408     block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
18409     block.item = replace(block.item, 'gm')
18410       (/bull/g, block.bullet)
18411       ();
18412     
18413     block.list = replace(block.list)
18414       (/bull/g, block.bullet)
18415       ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
18416       ('def', '\\n+(?=' + block.def.source + ')')
18417       ();
18418     
18419     block.blockquote = replace(block.blockquote)
18420       ('def', block.def)
18421       ();
18422     
18423     block._tag = '(?!(?:'
18424       + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
18425       + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
18426       + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
18427     
18428     block.html = replace(block.html)
18429       ('comment', /<!--[\s\S]*?-->/)
18430       ('closed', /<(tag)[\s\S]+?<\/\1>/)
18431       ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
18432       (/tag/g, block._tag)
18433       ();
18434     
18435     block.paragraph = replace(block.paragraph)
18436       ('hr', block.hr)
18437       ('heading', block.heading)
18438       ('lheading', block.lheading)
18439       ('blockquote', block.blockquote)
18440       ('tag', '<' + block._tag)
18441       ('def', block.def)
18442       ();
18443     
18444     /**
18445      * Normal Block Grammar
18446      */
18447     
18448     block.normal = merge({}, block);
18449     
18450     /**
18451      * GFM Block Grammar
18452      */
18453     
18454     block.gfm = merge({}, block.normal, {
18455       fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
18456       paragraph: /^/,
18457       heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
18458     });
18459     
18460     block.gfm.paragraph = replace(block.paragraph)
18461       ('(?!', '(?!'
18462         + block.gfm.fences.source.replace('\\1', '\\2') + '|'
18463         + block.list.source.replace('\\1', '\\3') + '|')
18464       ();
18465     
18466     /**
18467      * GFM + Tables Block Grammar
18468      */
18469     
18470     block.tables = merge({}, block.gfm, {
18471       nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
18472       table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
18473     });
18474     
18475     /**
18476      * Block Lexer
18477      */
18478     
18479     var Lexer = function (options) {
18480       this.tokens = [];
18481       this.tokens.links = {};
18482       this.options = options || marked.defaults;
18483       this.rules = block.normal;
18484     
18485       if (this.options.gfm) {
18486         if (this.options.tables) {
18487           this.rules = block.tables;
18488         } else {
18489           this.rules = block.gfm;
18490         }
18491       }
18492     }
18493     
18494     /**
18495      * Expose Block Rules
18496      */
18497     
18498     Lexer.rules = block;
18499     
18500     /**
18501      * Static Lex Method
18502      */
18503     
18504     Lexer.lex = function(src, options) {
18505       var lexer = new Lexer(options);
18506       return lexer.lex(src);
18507     };
18508     
18509     /**
18510      * Preprocessing
18511      */
18512     
18513     Lexer.prototype.lex = function(src) {
18514       src = src
18515         .replace(/\r\n|\r/g, '\n')
18516         .replace(/\t/g, '    ')
18517         .replace(/\u00a0/g, ' ')
18518         .replace(/\u2424/g, '\n');
18519     
18520       return this.token(src, true);
18521     };
18522     
18523     /**
18524      * Lexing
18525      */
18526     
18527     Lexer.prototype.token = function(src, top, bq) {
18528       var src = src.replace(/^ +$/gm, '')
18529         , next
18530         , loose
18531         , cap
18532         , bull
18533         , b
18534         , item
18535         , space
18536         , i
18537         , l;
18538     
18539       while (src) {
18540         // newline
18541         if (cap = this.rules.newline.exec(src)) {
18542           src = src.substring(cap[0].length);
18543           if (cap[0].length > 1) {
18544             this.tokens.push({
18545               type: 'space'
18546             });
18547           }
18548         }
18549     
18550         // code
18551         if (cap = this.rules.code.exec(src)) {
18552           src = src.substring(cap[0].length);
18553           cap = cap[0].replace(/^ {4}/gm, '');
18554           this.tokens.push({
18555             type: 'code',
18556             text: !this.options.pedantic
18557               ? cap.replace(/\n+$/, '')
18558               : cap
18559           });
18560           continue;
18561         }
18562     
18563         // fences (gfm)
18564         if (cap = this.rules.fences.exec(src)) {
18565           src = src.substring(cap[0].length);
18566           this.tokens.push({
18567             type: 'code',
18568             lang: cap[2],
18569             text: cap[3] || ''
18570           });
18571           continue;
18572         }
18573     
18574         // heading
18575         if (cap = this.rules.heading.exec(src)) {
18576           src = src.substring(cap[0].length);
18577           this.tokens.push({
18578             type: 'heading',
18579             depth: cap[1].length,
18580             text: cap[2]
18581           });
18582           continue;
18583         }
18584     
18585         // table no leading pipe (gfm)
18586         if (top && (cap = this.rules.nptable.exec(src))) {
18587           src = src.substring(cap[0].length);
18588     
18589           item = {
18590             type: 'table',
18591             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
18592             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
18593             cells: cap[3].replace(/\n$/, '').split('\n')
18594           };
18595     
18596           for (i = 0; i < item.align.length; i++) {
18597             if (/^ *-+: *$/.test(item.align[i])) {
18598               item.align[i] = 'right';
18599             } else if (/^ *:-+: *$/.test(item.align[i])) {
18600               item.align[i] = 'center';
18601             } else if (/^ *:-+ *$/.test(item.align[i])) {
18602               item.align[i] = 'left';
18603             } else {
18604               item.align[i] = null;
18605             }
18606           }
18607     
18608           for (i = 0; i < item.cells.length; i++) {
18609             item.cells[i] = item.cells[i].split(/ *\| */);
18610           }
18611     
18612           this.tokens.push(item);
18613     
18614           continue;
18615         }
18616     
18617         // lheading
18618         if (cap = this.rules.lheading.exec(src)) {
18619           src = src.substring(cap[0].length);
18620           this.tokens.push({
18621             type: 'heading',
18622             depth: cap[2] === '=' ? 1 : 2,
18623             text: cap[1]
18624           });
18625           continue;
18626         }
18627     
18628         // hr
18629         if (cap = this.rules.hr.exec(src)) {
18630           src = src.substring(cap[0].length);
18631           this.tokens.push({
18632             type: 'hr'
18633           });
18634           continue;
18635         }
18636     
18637         // blockquote
18638         if (cap = this.rules.blockquote.exec(src)) {
18639           src = src.substring(cap[0].length);
18640     
18641           this.tokens.push({
18642             type: 'blockquote_start'
18643           });
18644     
18645           cap = cap[0].replace(/^ *> ?/gm, '');
18646     
18647           // Pass `top` to keep the current
18648           // "toplevel" state. This is exactly
18649           // how markdown.pl works.
18650           this.token(cap, top, true);
18651     
18652           this.tokens.push({
18653             type: 'blockquote_end'
18654           });
18655     
18656           continue;
18657         }
18658     
18659         // list
18660         if (cap = this.rules.list.exec(src)) {
18661           src = src.substring(cap[0].length);
18662           bull = cap[2];
18663     
18664           this.tokens.push({
18665             type: 'list_start',
18666             ordered: bull.length > 1
18667           });
18668     
18669           // Get each top-level item.
18670           cap = cap[0].match(this.rules.item);
18671     
18672           next = false;
18673           l = cap.length;
18674           i = 0;
18675     
18676           for (; i < l; i++) {
18677             item = cap[i];
18678     
18679             // Remove the list item's bullet
18680             // so it is seen as the next token.
18681             space = item.length;
18682             item = item.replace(/^ *([*+-]|\d+\.) +/, '');
18683     
18684             // Outdent whatever the
18685             // list item contains. Hacky.
18686             if (~item.indexOf('\n ')) {
18687               space -= item.length;
18688               item = !this.options.pedantic
18689                 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
18690                 : item.replace(/^ {1,4}/gm, '');
18691             }
18692     
18693             // Determine whether the next list item belongs here.
18694             // Backpedal if it does not belong in this list.
18695             if (this.options.smartLists && i !== l - 1) {
18696               b = block.bullet.exec(cap[i + 1])[0];
18697               if (bull !== b && !(bull.length > 1 && b.length > 1)) {
18698                 src = cap.slice(i + 1).join('\n') + src;
18699                 i = l - 1;
18700               }
18701             }
18702     
18703             // Determine whether item is loose or not.
18704             // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
18705             // for discount behavior.
18706             loose = next || /\n\n(?!\s*$)/.test(item);
18707             if (i !== l - 1) {
18708               next = item.charAt(item.length - 1) === '\n';
18709               if (!loose) { loose = next; }
18710             }
18711     
18712             this.tokens.push({
18713               type: loose
18714                 ? 'loose_item_start'
18715                 : 'list_item_start'
18716             });
18717     
18718             // Recurse.
18719             this.token(item, false, bq);
18720     
18721             this.tokens.push({
18722               type: 'list_item_end'
18723             });
18724           }
18725     
18726           this.tokens.push({
18727             type: 'list_end'
18728           });
18729     
18730           continue;
18731         }
18732     
18733         // html
18734         if (cap = this.rules.html.exec(src)) {
18735           src = src.substring(cap[0].length);
18736           this.tokens.push({
18737             type: this.options.sanitize
18738               ? 'paragraph'
18739               : 'html',
18740             pre: !this.options.sanitizer
18741               && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
18742             text: cap[0]
18743           });
18744           continue;
18745         }
18746     
18747         // def
18748         if ((!bq && top) && (cap = this.rules.def.exec(src))) {
18749           src = src.substring(cap[0].length);
18750           this.tokens.links[cap[1].toLowerCase()] = {
18751             href: cap[2],
18752             title: cap[3]
18753           };
18754           continue;
18755         }
18756     
18757         // table (gfm)
18758         if (top && (cap = this.rules.table.exec(src))) {
18759           src = src.substring(cap[0].length);
18760     
18761           item = {
18762             type: 'table',
18763             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
18764             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
18765             cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
18766           };
18767     
18768           for (i = 0; i < item.align.length; i++) {
18769             if (/^ *-+: *$/.test(item.align[i])) {
18770               item.align[i] = 'right';
18771             } else if (/^ *:-+: *$/.test(item.align[i])) {
18772               item.align[i] = 'center';
18773             } else if (/^ *:-+ *$/.test(item.align[i])) {
18774               item.align[i] = 'left';
18775             } else {
18776               item.align[i] = null;
18777             }
18778           }
18779     
18780           for (i = 0; i < item.cells.length; i++) {
18781             item.cells[i] = item.cells[i]
18782               .replace(/^ *\| *| *\| *$/g, '')
18783               .split(/ *\| */);
18784           }
18785     
18786           this.tokens.push(item);
18787     
18788           continue;
18789         }
18790     
18791         // top-level paragraph
18792         if (top && (cap = this.rules.paragraph.exec(src))) {
18793           src = src.substring(cap[0].length);
18794           this.tokens.push({
18795             type: 'paragraph',
18796             text: cap[1].charAt(cap[1].length - 1) === '\n'
18797               ? cap[1].slice(0, -1)
18798               : cap[1]
18799           });
18800           continue;
18801         }
18802     
18803         // text
18804         if (cap = this.rules.text.exec(src)) {
18805           // Top-level should never reach here.
18806           src = src.substring(cap[0].length);
18807           this.tokens.push({
18808             type: 'text',
18809             text: cap[0]
18810           });
18811           continue;
18812         }
18813     
18814         if (src) {
18815           throw new
18816             Error('Infinite loop on byte: ' + src.charCodeAt(0));
18817         }
18818       }
18819     
18820       return this.tokens;
18821     };
18822     
18823     /**
18824      * Inline-Level Grammar
18825      */
18826     
18827     var inline = {
18828       escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
18829       autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
18830       url: noop,
18831       tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
18832       link: /^!?\[(inside)\]\(href\)/,
18833       reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
18834       nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
18835       strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
18836       em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
18837       code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
18838       br: /^ {2,}\n(?!\s*$)/,
18839       del: noop,
18840       text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
18841     };
18842     
18843     inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
18844     inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
18845     
18846     inline.link = replace(inline.link)
18847       ('inside', inline._inside)
18848       ('href', inline._href)
18849       ();
18850     
18851     inline.reflink = replace(inline.reflink)
18852       ('inside', inline._inside)
18853       ();
18854     
18855     /**
18856      * Normal Inline Grammar
18857      */
18858     
18859     inline.normal = merge({}, inline);
18860     
18861     /**
18862      * Pedantic Inline Grammar
18863      */
18864     
18865     inline.pedantic = merge({}, inline.normal, {
18866       strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
18867       em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
18868     });
18869     
18870     /**
18871      * GFM Inline Grammar
18872      */
18873     
18874     inline.gfm = merge({}, inline.normal, {
18875       escape: replace(inline.escape)('])', '~|])')(),
18876       url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
18877       del: /^~~(?=\S)([\s\S]*?\S)~~/,
18878       text: replace(inline.text)
18879         (']|', '~]|')
18880         ('|', '|https?://|')
18881         ()
18882     });
18883     
18884     /**
18885      * GFM + Line Breaks Inline Grammar
18886      */
18887     
18888     inline.breaks = merge({}, inline.gfm, {
18889       br: replace(inline.br)('{2,}', '*')(),
18890       text: replace(inline.gfm.text)('{2,}', '*')()
18891     });
18892     
18893     /**
18894      * Inline Lexer & Compiler
18895      */
18896     
18897     var InlineLexer  = function (links, options) {
18898       this.options = options || marked.defaults;
18899       this.links = links;
18900       this.rules = inline.normal;
18901       this.renderer = this.options.renderer || new Renderer;
18902       this.renderer.options = this.options;
18903     
18904       if (!this.links) {
18905         throw new
18906           Error('Tokens array requires a `links` property.');
18907       }
18908     
18909       if (this.options.gfm) {
18910         if (this.options.breaks) {
18911           this.rules = inline.breaks;
18912         } else {
18913           this.rules = inline.gfm;
18914         }
18915       } else if (this.options.pedantic) {
18916         this.rules = inline.pedantic;
18917       }
18918     }
18919     
18920     /**
18921      * Expose Inline Rules
18922      */
18923     
18924     InlineLexer.rules = inline;
18925     
18926     /**
18927      * Static Lexing/Compiling Method
18928      */
18929     
18930     InlineLexer.output = function(src, links, options) {
18931       var inline = new InlineLexer(links, options);
18932       return inline.output(src);
18933     };
18934     
18935     /**
18936      * Lexing/Compiling
18937      */
18938     
18939     InlineLexer.prototype.output = function(src) {
18940       var out = ''
18941         , link
18942         , text
18943         , href
18944         , cap;
18945     
18946       while (src) {
18947         // escape
18948         if (cap = this.rules.escape.exec(src)) {
18949           src = src.substring(cap[0].length);
18950           out += cap[1];
18951           continue;
18952         }
18953     
18954         // autolink
18955         if (cap = this.rules.autolink.exec(src)) {
18956           src = src.substring(cap[0].length);
18957           if (cap[2] === '@') {
18958             text = cap[1].charAt(6) === ':'
18959               ? this.mangle(cap[1].substring(7))
18960               : this.mangle(cap[1]);
18961             href = this.mangle('mailto:') + text;
18962           } else {
18963             text = escape(cap[1]);
18964             href = text;
18965           }
18966           out += this.renderer.link(href, null, text);
18967           continue;
18968         }
18969     
18970         // url (gfm)
18971         if (!this.inLink && (cap = this.rules.url.exec(src))) {
18972           src = src.substring(cap[0].length);
18973           text = escape(cap[1]);
18974           href = text;
18975           out += this.renderer.link(href, null, text);
18976           continue;
18977         }
18978     
18979         // tag
18980         if (cap = this.rules.tag.exec(src)) {
18981           if (!this.inLink && /^<a /i.test(cap[0])) {
18982             this.inLink = true;
18983           } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
18984             this.inLink = false;
18985           }
18986           src = src.substring(cap[0].length);
18987           out += this.options.sanitize
18988             ? this.options.sanitizer
18989               ? this.options.sanitizer(cap[0])
18990               : escape(cap[0])
18991             : cap[0];
18992           continue;
18993         }
18994     
18995         // link
18996         if (cap = this.rules.link.exec(src)) {
18997           src = src.substring(cap[0].length);
18998           this.inLink = true;
18999           out += this.outputLink(cap, {
19000             href: cap[2],
19001             title: cap[3]
19002           });
19003           this.inLink = false;
19004           continue;
19005         }
19006     
19007         // reflink, nolink
19008         if ((cap = this.rules.reflink.exec(src))
19009             || (cap = this.rules.nolink.exec(src))) {
19010           src = src.substring(cap[0].length);
19011           link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
19012           link = this.links[link.toLowerCase()];
19013           if (!link || !link.href) {
19014             out += cap[0].charAt(0);
19015             src = cap[0].substring(1) + src;
19016             continue;
19017           }
19018           this.inLink = true;
19019           out += this.outputLink(cap, link);
19020           this.inLink = false;
19021           continue;
19022         }
19023     
19024         // strong
19025         if (cap = this.rules.strong.exec(src)) {
19026           src = src.substring(cap[0].length);
19027           out += this.renderer.strong(this.output(cap[2] || cap[1]));
19028           continue;
19029         }
19030     
19031         // em
19032         if (cap = this.rules.em.exec(src)) {
19033           src = src.substring(cap[0].length);
19034           out += this.renderer.em(this.output(cap[2] || cap[1]));
19035           continue;
19036         }
19037     
19038         // code
19039         if (cap = this.rules.code.exec(src)) {
19040           src = src.substring(cap[0].length);
19041           out += this.renderer.codespan(escape(cap[2], true));
19042           continue;
19043         }
19044     
19045         // br
19046         if (cap = this.rules.br.exec(src)) {
19047           src = src.substring(cap[0].length);
19048           out += this.renderer.br();
19049           continue;
19050         }
19051     
19052         // del (gfm)
19053         if (cap = this.rules.del.exec(src)) {
19054           src = src.substring(cap[0].length);
19055           out += this.renderer.del(this.output(cap[1]));
19056           continue;
19057         }
19058     
19059         // text
19060         if (cap = this.rules.text.exec(src)) {
19061           src = src.substring(cap[0].length);
19062           out += this.renderer.text(escape(this.smartypants(cap[0])));
19063           continue;
19064         }
19065     
19066         if (src) {
19067           throw new
19068             Error('Infinite loop on byte: ' + src.charCodeAt(0));
19069         }
19070       }
19071     
19072       return out;
19073     };
19074     
19075     /**
19076      * Compile Link
19077      */
19078     
19079     InlineLexer.prototype.outputLink = function(cap, link) {
19080       var href = escape(link.href)
19081         , title = link.title ? escape(link.title) : null;
19082     
19083       return cap[0].charAt(0) !== '!'
19084         ? this.renderer.link(href, title, this.output(cap[1]))
19085         : this.renderer.image(href, title, escape(cap[1]));
19086     };
19087     
19088     /**
19089      * Smartypants Transformations
19090      */
19091     
19092     InlineLexer.prototype.smartypants = function(text) {
19093       if (!this.options.smartypants)  { return text; }
19094       return text
19095         // em-dashes
19096         .replace(/---/g, '\u2014')
19097         // en-dashes
19098         .replace(/--/g, '\u2013')
19099         // opening singles
19100         .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
19101         // closing singles & apostrophes
19102         .replace(/'/g, '\u2019')
19103         // opening doubles
19104         .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
19105         // closing doubles
19106         .replace(/"/g, '\u201d')
19107         // ellipses
19108         .replace(/\.{3}/g, '\u2026');
19109     };
19110     
19111     /**
19112      * Mangle Links
19113      */
19114     
19115     InlineLexer.prototype.mangle = function(text) {
19116       if (!this.options.mangle) { return text; }
19117       var out = ''
19118         , l = text.length
19119         , i = 0
19120         , ch;
19121     
19122       for (; i < l; i++) {
19123         ch = text.charCodeAt(i);
19124         if (Math.random() > 0.5) {
19125           ch = 'x' + ch.toString(16);
19126         }
19127         out += '&#' + ch + ';';
19128       }
19129     
19130       return out;
19131     };
19132     
19133     /**
19134      * Renderer
19135      */
19136     
19137      /**
19138          * eval:var:Renderer
19139     */
19140     
19141     var Renderer   = function (options) {
19142       this.options = options || {};
19143     }
19144     
19145     Renderer.prototype.code = function(code, lang, escaped) {
19146       if (this.options.highlight) {
19147         var out = this.options.highlight(code, lang);
19148         if (out != null && out !== code) {
19149           escaped = true;
19150           code = out;
19151         }
19152       } else {
19153             // hack!!! - it's already escapeD?
19154             escaped = true;
19155       }
19156     
19157       if (!lang) {
19158         return '<pre><code>'
19159           + (escaped ? code : escape(code, true))
19160           + '\n</code></pre>';
19161       }
19162     
19163       return '<pre><code class="'
19164         + this.options.langPrefix
19165         + escape(lang, true)
19166         + '">'
19167         + (escaped ? code : escape(code, true))
19168         + '\n</code></pre>\n';
19169     };
19170     
19171     Renderer.prototype.blockquote = function(quote) {
19172       return '<blockquote>\n' + quote + '</blockquote>\n';
19173     };
19174     
19175     Renderer.prototype.html = function(html) {
19176       return html;
19177     };
19178     
19179     Renderer.prototype.heading = function(text, level, raw) {
19180       return '<h'
19181         + level
19182         + ' id="'
19183         + this.options.headerPrefix
19184         + raw.toLowerCase().replace(/[^\w]+/g, '-')
19185         + '">'
19186         + text
19187         + '</h'
19188         + level
19189         + '>\n';
19190     };
19191     
19192     Renderer.prototype.hr = function() {
19193       return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
19194     };
19195     
19196     Renderer.prototype.list = function(body, ordered) {
19197       var type = ordered ? 'ol' : 'ul';
19198       return '<' + type + '>\n' + body + '</' + type + '>\n';
19199     };
19200     
19201     Renderer.prototype.listitem = function(text) {
19202       return '<li>' + text + '</li>\n';
19203     };
19204     
19205     Renderer.prototype.paragraph = function(text) {
19206       return '<p>' + text + '</p>\n';
19207     };
19208     
19209     Renderer.prototype.table = function(header, body) {
19210       return '<table class="table table-striped">\n'
19211         + '<thead>\n'
19212         + header
19213         + '</thead>\n'
19214         + '<tbody>\n'
19215         + body
19216         + '</tbody>\n'
19217         + '</table>\n';
19218     };
19219     
19220     Renderer.prototype.tablerow = function(content) {
19221       return '<tr>\n' + content + '</tr>\n';
19222     };
19223     
19224     Renderer.prototype.tablecell = function(content, flags) {
19225       var type = flags.header ? 'th' : 'td';
19226       var tag = flags.align
19227         ? '<' + type + ' style="text-align:' + flags.align + '">'
19228         : '<' + type + '>';
19229       return tag + content + '</' + type + '>\n';
19230     };
19231     
19232     // span level renderer
19233     Renderer.prototype.strong = function(text) {
19234       return '<strong>' + text + '</strong>';
19235     };
19236     
19237     Renderer.prototype.em = function(text) {
19238       return '<em>' + text + '</em>';
19239     };
19240     
19241     Renderer.prototype.codespan = function(text) {
19242       return '<code>' + text + '</code>';
19243     };
19244     
19245     Renderer.prototype.br = function() {
19246       return this.options.xhtml ? '<br/>' : '<br>';
19247     };
19248     
19249     Renderer.prototype.del = function(text) {
19250       return '<del>' + text + '</del>';
19251     };
19252     
19253     Renderer.prototype.link = function(href, title, text) {
19254       if (this.options.sanitize) {
19255         try {
19256           var prot = decodeURIComponent(unescape(href))
19257             .replace(/[^\w:]/g, '')
19258             .toLowerCase();
19259         } catch (e) {
19260           return '';
19261         }
19262         if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
19263           return '';
19264         }
19265       }
19266       var out = '<a href="' + href + '"';
19267       if (title) {
19268         out += ' title="' + title + '"';
19269       }
19270       out += '>' + text + '</a>';
19271       return out;
19272     };
19273     
19274     Renderer.prototype.image = function(href, title, text) {
19275       var out = '<img src="' + href + '" alt="' + text + '"';
19276       if (title) {
19277         out += ' title="' + title + '"';
19278       }
19279       out += this.options.xhtml ? '/>' : '>';
19280       return out;
19281     };
19282     
19283     Renderer.prototype.text = function(text) {
19284       return text;
19285     };
19286     
19287     /**
19288      * Parsing & Compiling
19289      */
19290          /**
19291          * eval:var:Parser
19292     */
19293     
19294     var Parser= function (options) {
19295       this.tokens = [];
19296       this.token = null;
19297       this.options = options || marked.defaults;
19298       this.options.renderer = this.options.renderer || new Renderer;
19299       this.renderer = this.options.renderer;
19300       this.renderer.options = this.options;
19301     }
19302     
19303     /**
19304      * Static Parse Method
19305      */
19306     
19307     Parser.parse = function(src, options, renderer) {
19308       var parser = new Parser(options, renderer);
19309       return parser.parse(src);
19310     };
19311     
19312     /**
19313      * Parse Loop
19314      */
19315     
19316     Parser.prototype.parse = function(src) {
19317       this.inline = new InlineLexer(src.links, this.options, this.renderer);
19318       this.tokens = src.reverse();
19319     
19320       var out = '';
19321       while (this.next()) {
19322         out += this.tok();
19323       }
19324     
19325       return out;
19326     };
19327     
19328     /**
19329      * Next Token
19330      */
19331     
19332     Parser.prototype.next = function() {
19333       return this.token = this.tokens.pop();
19334     };
19335     
19336     /**
19337      * Preview Next Token
19338      */
19339     
19340     Parser.prototype.peek = function() {
19341       return this.tokens[this.tokens.length - 1] || 0;
19342     };
19343     
19344     /**
19345      * Parse Text Tokens
19346      */
19347     
19348     Parser.prototype.parseText = function() {
19349       var body = this.token.text;
19350     
19351       while (this.peek().type === 'text') {
19352         body += '\n' + this.next().text;
19353       }
19354     
19355       return this.inline.output(body);
19356     };
19357     
19358     /**
19359      * Parse Current Token
19360      */
19361     
19362     Parser.prototype.tok = function() {
19363       switch (this.token.type) {
19364         case 'space': {
19365           return '';
19366         }
19367         case 'hr': {
19368           return this.renderer.hr();
19369         }
19370         case 'heading': {
19371           return this.renderer.heading(
19372             this.inline.output(this.token.text),
19373             this.token.depth,
19374             this.token.text);
19375         }
19376         case 'code': {
19377           return this.renderer.code(this.token.text,
19378             this.token.lang,
19379             this.token.escaped);
19380         }
19381         case 'table': {
19382           var header = ''
19383             , body = ''
19384             , i
19385             , row
19386             , cell
19387             , flags
19388             , j;
19389     
19390           // header
19391           cell = '';
19392           for (i = 0; i < this.token.header.length; i++) {
19393             flags = { header: true, align: this.token.align[i] };
19394             cell += this.renderer.tablecell(
19395               this.inline.output(this.token.header[i]),
19396               { header: true, align: this.token.align[i] }
19397             );
19398           }
19399           header += this.renderer.tablerow(cell);
19400     
19401           for (i = 0; i < this.token.cells.length; i++) {
19402             row = this.token.cells[i];
19403     
19404             cell = '';
19405             for (j = 0; j < row.length; j++) {
19406               cell += this.renderer.tablecell(
19407                 this.inline.output(row[j]),
19408                 { header: false, align: this.token.align[j] }
19409               );
19410             }
19411     
19412             body += this.renderer.tablerow(cell);
19413           }
19414           return this.renderer.table(header, body);
19415         }
19416         case 'blockquote_start': {
19417           var body = '';
19418     
19419           while (this.next().type !== 'blockquote_end') {
19420             body += this.tok();
19421           }
19422     
19423           return this.renderer.blockquote(body);
19424         }
19425         case 'list_start': {
19426           var body = ''
19427             , ordered = this.token.ordered;
19428     
19429           while (this.next().type !== 'list_end') {
19430             body += this.tok();
19431           }
19432     
19433           return this.renderer.list(body, ordered);
19434         }
19435         case 'list_item_start': {
19436           var body = '';
19437     
19438           while (this.next().type !== 'list_item_end') {
19439             body += this.token.type === 'text'
19440               ? this.parseText()
19441               : this.tok();
19442           }
19443     
19444           return this.renderer.listitem(body);
19445         }
19446         case 'loose_item_start': {
19447           var body = '';
19448     
19449           while (this.next().type !== 'list_item_end') {
19450             body += this.tok();
19451           }
19452     
19453           return this.renderer.listitem(body);
19454         }
19455         case 'html': {
19456           var html = !this.token.pre && !this.options.pedantic
19457             ? this.inline.output(this.token.text)
19458             : this.token.text;
19459           return this.renderer.html(html);
19460         }
19461         case 'paragraph': {
19462           return this.renderer.paragraph(this.inline.output(this.token.text));
19463         }
19464         case 'text': {
19465           return this.renderer.paragraph(this.parseText());
19466         }
19467       }
19468     };
19469   
19470     
19471     /**
19472      * Marked
19473      */
19474          /**
19475          * eval:var:marked
19476     */
19477     var marked = function (src, opt, callback) {
19478       if (callback || typeof opt === 'function') {
19479         if (!callback) {
19480           callback = opt;
19481           opt = null;
19482         }
19483     
19484         opt = merge({}, marked.defaults, opt || {});
19485     
19486         var highlight = opt.highlight
19487           , tokens
19488           , pending
19489           , i = 0;
19490     
19491         try {
19492           tokens = Lexer.lex(src, opt)
19493         } catch (e) {
19494           return callback(e);
19495         }
19496     
19497         pending = tokens.length;
19498          /**
19499          * eval:var:done
19500     */
19501         var done = function(err) {
19502           if (err) {
19503             opt.highlight = highlight;
19504             return callback(err);
19505           }
19506     
19507           var out;
19508     
19509           try {
19510             out = Parser.parse(tokens, opt);
19511           } catch (e) {
19512             err = e;
19513           }
19514     
19515           opt.highlight = highlight;
19516     
19517           return err
19518             ? callback(err)
19519             : callback(null, out);
19520         };
19521     
19522         if (!highlight || highlight.length < 3) {
19523           return done();
19524         }
19525     
19526         delete opt.highlight;
19527     
19528         if (!pending) { return done(); }
19529     
19530         for (; i < tokens.length; i++) {
19531           (function(token) {
19532             if (token.type !== 'code') {
19533               return --pending || done();
19534             }
19535             return highlight(token.text, token.lang, function(err, code) {
19536               if (err) { return done(err); }
19537               if (code == null || code === token.text) {
19538                 return --pending || done();
19539               }
19540               token.text = code;
19541               token.escaped = true;
19542               --pending || done();
19543             });
19544           })(tokens[i]);
19545         }
19546     
19547         return;
19548       }
19549       try {
19550         if (opt) { opt = merge({}, marked.defaults, opt); }
19551         return Parser.parse(Lexer.lex(src, opt), opt);
19552       } catch (e) {
19553         e.message += '\nPlease report this to https://github.com/chjj/marked.';
19554         if ((opt || marked.defaults).silent) {
19555           return '<p>An error occured:</p><pre>'
19556             + escape(e.message + '', true)
19557             + '</pre>';
19558         }
19559         throw e;
19560       }
19561     }
19562     
19563     /**
19564      * Options
19565      */
19566     
19567     marked.options =
19568     marked.setOptions = function(opt) {
19569       merge(marked.defaults, opt);
19570       return marked;
19571     };
19572     
19573     marked.defaults = {
19574       gfm: true,
19575       tables: true,
19576       breaks: false,
19577       pedantic: false,
19578       sanitize: false,
19579       sanitizer: null,
19580       mangle: true,
19581       smartLists: false,
19582       silent: false,
19583       highlight: null,
19584       langPrefix: 'lang-',
19585       smartypants: false,
19586       headerPrefix: '',
19587       renderer: new Renderer,
19588       xhtml: false
19589     };
19590     
19591     /**
19592      * Expose
19593      */
19594     
19595     marked.Parser = Parser;
19596     marked.parser = Parser.parse;
19597     
19598     marked.Renderer = Renderer;
19599     
19600     marked.Lexer = Lexer;
19601     marked.lexer = Lexer.lex;
19602     
19603     marked.InlineLexer = InlineLexer;
19604     marked.inlineLexer = InlineLexer.output;
19605     
19606     marked.parse = marked;
19607     
19608     Roo.Markdown.marked = marked;
19609
19610 })();/*
19611  * Based on:
19612  * Ext JS Library 1.1.1
19613  * Copyright(c) 2006-2007, Ext JS, LLC.
19614  *
19615  * Originally Released Under LGPL - original licence link has changed is not relivant.
19616  *
19617  * Fork - LGPL
19618  * <script type="text/javascript">
19619  */
19620
19621
19622
19623 /*
19624  * These classes are derivatives of the similarly named classes in the YUI Library.
19625  * The original license:
19626  * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
19627  * Code licensed under the BSD License:
19628  * http://developer.yahoo.net/yui/license.txt
19629  */
19630
19631 (function() {
19632
19633 var Event=Roo.EventManager;
19634 var Dom=Roo.lib.Dom;
19635
19636 /**
19637  * @class Roo.dd.DragDrop
19638  * @extends Roo.util.Observable
19639  * Defines the interface and base operation of items that that can be
19640  * dragged or can be drop targets.  It was designed to be extended, overriding
19641  * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
19642  * Up to three html elements can be associated with a DragDrop instance:
19643  * <ul>
19644  * <li>linked element: the element that is passed into the constructor.
19645  * This is the element which defines the boundaries for interaction with
19646  * other DragDrop objects.</li>
19647  * <li>handle element(s): The drag operation only occurs if the element that
19648  * was clicked matches a handle element.  By default this is the linked
19649  * element, but there are times that you will want only a portion of the
19650  * linked element to initiate the drag operation, and the setHandleElId()
19651  * method provides a way to define this.</li>
19652  * <li>drag element: this represents the element that would be moved along
19653  * with the cursor during a drag operation.  By default, this is the linked
19654  * element itself as in {@link Roo.dd.DD}.  setDragElId() lets you define
19655  * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
19656  * </li>
19657  * </ul>
19658  * This class should not be instantiated until the onload event to ensure that
19659  * the associated elements are available.
19660  * The following would define a DragDrop obj that would interact with any
19661  * other DragDrop obj in the "group1" group:
19662  * <pre>
19663  *  dd = new Roo.dd.DragDrop("div1", "group1");
19664  * </pre>
19665  * Since none of the event handlers have been implemented, nothing would
19666  * actually happen if you were to run the code above.  Normally you would
19667  * override this class or one of the default implementations, but you can
19668  * also override the methods you want on an instance of the class...
19669  * <pre>
19670  *  dd.onDragDrop = function(e, id) {
19671  *  &nbsp;&nbsp;alert("dd was dropped on " + id);
19672  *  }
19673  * </pre>
19674  * @constructor
19675  * @param {String} id of the element that is linked to this instance
19676  * @param {String} sGroup the group of related DragDrop objects
19677  * @param {object} config an object containing configurable attributes
19678  *                Valid properties for DragDrop:
19679  *                    padding, isTarget, maintainOffset, primaryButtonOnly
19680  */
19681 Roo.dd.DragDrop = function(id, sGroup, config) {
19682     if (id) {
19683         this.init(id, sGroup, config);
19684     }
19685     
19686 };
19687
19688 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
19689
19690     /**
19691      * The id of the element associated with this object.  This is what we
19692      * refer to as the "linked element" because the size and position of
19693      * this element is used to determine when the drag and drop objects have
19694      * interacted.
19695      * @property id
19696      * @type String
19697      */
19698     id: null,
19699
19700     /**
19701      * Configuration attributes passed into the constructor
19702      * @property config
19703      * @type object
19704      */
19705     config: null,
19706
19707     /**
19708      * The id of the element that will be dragged.  By default this is same
19709      * as the linked element , but could be changed to another element. Ex:
19710      * Roo.dd.DDProxy
19711      * @property dragElId
19712      * @type String
19713      * @private
19714      */
19715     dragElId: null,
19716
19717     /**
19718      * the id of the element that initiates the drag operation.  By default
19719      * this is the linked element, but could be changed to be a child of this
19720      * element.  This lets us do things like only starting the drag when the
19721      * header element within the linked html element is clicked.
19722      * @property handleElId
19723      * @type String
19724      * @private
19725      */
19726     handleElId: null,
19727
19728     /**
19729      * An associative array of HTML tags that will be ignored if clicked.
19730      * @property invalidHandleTypes
19731      * @type {string: string}
19732      */
19733     invalidHandleTypes: null,
19734
19735     /**
19736      * An associative array of ids for elements that will be ignored if clicked
19737      * @property invalidHandleIds
19738      * @type {string: string}
19739      */
19740     invalidHandleIds: null,
19741
19742     /**
19743      * An indexted array of css class names for elements that will be ignored
19744      * if clicked.
19745      * @property invalidHandleClasses
19746      * @type string[]
19747      */
19748     invalidHandleClasses: null,
19749
19750     /**
19751      * The linked element's absolute X position at the time the drag was
19752      * started
19753      * @property startPageX
19754      * @type int
19755      * @private
19756      */
19757     startPageX: 0,
19758
19759     /**
19760      * The linked element's absolute X position at the time the drag was
19761      * started
19762      * @property startPageY
19763      * @type int
19764      * @private
19765      */
19766     startPageY: 0,
19767
19768     /**
19769      * The group defines a logical collection of DragDrop objects that are
19770      * related.  Instances only get events when interacting with other
19771      * DragDrop object in the same group.  This lets us define multiple
19772      * groups using a single DragDrop subclass if we want.
19773      * @property groups
19774      * @type {string: string}
19775      */
19776     groups: null,
19777
19778     /**
19779      * Individual drag/drop instances can be locked.  This will prevent
19780      * onmousedown start drag.
19781      * @property locked
19782      * @type boolean
19783      * @private
19784      */
19785     locked: false,
19786
19787     /**
19788      * Lock this instance
19789      * @method lock
19790      */
19791     lock: function() { this.locked = true; },
19792
19793     /**
19794      * Unlock this instace
19795      * @method unlock
19796      */
19797     unlock: function() { this.locked = false; },
19798
19799     /**
19800      * By default, all insances can be a drop target.  This can be disabled by
19801      * setting isTarget to false.
19802      * @method isTarget
19803      * @type boolean
19804      */
19805     isTarget: true,
19806
19807     /**
19808      * The padding configured for this drag and drop object for calculating
19809      * the drop zone intersection with this object.
19810      * @method padding
19811      * @type int[]
19812      */
19813     padding: null,
19814
19815     /**
19816      * Cached reference to the linked element
19817      * @property _domRef
19818      * @private
19819      */
19820     _domRef: null,
19821
19822     /**
19823      * Internal typeof flag
19824      * @property __ygDragDrop
19825      * @private
19826      */
19827     __ygDragDrop: true,
19828
19829     /**
19830      * Set to true when horizontal contraints are applied
19831      * @property constrainX
19832      * @type boolean
19833      * @private
19834      */
19835     constrainX: false,
19836
19837     /**
19838      * Set to true when vertical contraints are applied
19839      * @property constrainY
19840      * @type boolean
19841      * @private
19842      */
19843     constrainY: false,
19844
19845     /**
19846      * The left constraint
19847      * @property minX
19848      * @type int
19849      * @private
19850      */
19851     minX: 0,
19852
19853     /**
19854      * The right constraint
19855      * @property maxX
19856      * @type int
19857      * @private
19858      */
19859     maxX: 0,
19860
19861     /**
19862      * The up constraint
19863      * @property minY
19864      * @type int
19865      * @type int
19866      * @private
19867      */
19868     minY: 0,
19869
19870     /**
19871      * The down constraint
19872      * @property maxY
19873      * @type int
19874      * @private
19875      */
19876     maxY: 0,
19877
19878     /**
19879      * Maintain offsets when we resetconstraints.  Set to true when you want
19880      * the position of the element relative to its parent to stay the same
19881      * when the page changes
19882      *
19883      * @property maintainOffset
19884      * @type boolean
19885      */
19886     maintainOffset: false,
19887
19888     /**
19889      * Array of pixel locations the element will snap to if we specified a
19890      * horizontal graduation/interval.  This array is generated automatically
19891      * when you define a tick interval.
19892      * @property xTicks
19893      * @type int[]
19894      */
19895     xTicks: null,
19896
19897     /**
19898      * Array of pixel locations the element will snap to if we specified a
19899      * vertical graduation/interval.  This array is generated automatically
19900      * when you define a tick interval.
19901      * @property yTicks
19902      * @type int[]
19903      */
19904     yTicks: null,
19905
19906     /**
19907      * By default the drag and drop instance will only respond to the primary
19908      * button click (left button for a right-handed mouse).  Set to true to
19909      * allow drag and drop to start with any mouse click that is propogated
19910      * by the browser
19911      * @property primaryButtonOnly
19912      * @type boolean
19913      */
19914     primaryButtonOnly: true,
19915
19916     /**
19917      * The availabe property is false until the linked dom element is accessible.
19918      * @property available
19919      * @type boolean
19920      */
19921     available: false,
19922
19923     /**
19924      * By default, drags can only be initiated if the mousedown occurs in the
19925      * region the linked element is.  This is done in part to work around a
19926      * bug in some browsers that mis-report the mousedown if the previous
19927      * mouseup happened outside of the window.  This property is set to true
19928      * if outer handles are defined.
19929      *
19930      * @property hasOuterHandles
19931      * @type boolean
19932      * @default false
19933      */
19934     hasOuterHandles: false,
19935
19936     /**
19937      * Code that executes immediately before the startDrag event
19938      * @method b4StartDrag
19939      * @private
19940      */
19941     b4StartDrag: function(x, y) { },
19942
19943     /**
19944      * Abstract method called after a drag/drop object is clicked
19945      * and the drag or mousedown time thresholds have beeen met.
19946      * @method startDrag
19947      * @param {int} X click location
19948      * @param {int} Y click location
19949      */
19950     startDrag: function(x, y) { /* override this */ },
19951
19952     /**
19953      * Code that executes immediately before the onDrag event
19954      * @method b4Drag
19955      * @private
19956      */
19957     b4Drag: function(e) { },
19958
19959     /**
19960      * Abstract method called during the onMouseMove event while dragging an
19961      * object.
19962      * @method onDrag
19963      * @param {Event} e the mousemove event
19964      */
19965     onDrag: function(e) { /* override this */ },
19966
19967     /**
19968      * Abstract method called when this element fist begins hovering over
19969      * another DragDrop obj
19970      * @method onDragEnter
19971      * @param {Event} e the mousemove event
19972      * @param {String|DragDrop[]} id In POINT mode, the element
19973      * id this is hovering over.  In INTERSECT mode, an array of one or more
19974      * dragdrop items being hovered over.
19975      */
19976     onDragEnter: function(e, id) { /* override this */ },
19977
19978     /**
19979      * Code that executes immediately before the onDragOver event
19980      * @method b4DragOver
19981      * @private
19982      */
19983     b4DragOver: function(e) { },
19984
19985     /**
19986      * Abstract method called when this element is hovering over another
19987      * DragDrop obj
19988      * @method onDragOver
19989      * @param {Event} e the mousemove event
19990      * @param {String|DragDrop[]} id In POINT mode, the element
19991      * id this is hovering over.  In INTERSECT mode, an array of dd items
19992      * being hovered over.
19993      */
19994     onDragOver: function(e, id) { /* override this */ },
19995
19996     /**
19997      * Code that executes immediately before the onDragOut event
19998      * @method b4DragOut
19999      * @private
20000      */
20001     b4DragOut: function(e) { },
20002
20003     /**
20004      * Abstract method called when we are no longer hovering over an element
20005      * @method onDragOut
20006      * @param {Event} e the mousemove event
20007      * @param {String|DragDrop[]} id In POINT mode, the element
20008      * id this was hovering over.  In INTERSECT mode, an array of dd items
20009      * that the mouse is no longer over.
20010      */
20011     onDragOut: function(e, id) { /* override this */ },
20012
20013     /**
20014      * Code that executes immediately before the onDragDrop event
20015      * @method b4DragDrop
20016      * @private
20017      */
20018     b4DragDrop: function(e) { },
20019
20020     /**
20021      * Abstract method called when this item is dropped on another DragDrop
20022      * obj
20023      * @method onDragDrop
20024      * @param {Event} e the mouseup event
20025      * @param {String|DragDrop[]} id In POINT mode, the element
20026      * id this was dropped on.  In INTERSECT mode, an array of dd items this
20027      * was dropped on.
20028      */
20029     onDragDrop: function(e, id) { /* override this */ },
20030
20031     /**
20032      * Abstract method called when this item is dropped on an area with no
20033      * drop target
20034      * @method onInvalidDrop
20035      * @param {Event} e the mouseup event
20036      */
20037     onInvalidDrop: function(e) { /* override this */ },
20038
20039     /**
20040      * Code that executes immediately before the endDrag event
20041      * @method b4EndDrag
20042      * @private
20043      */
20044     b4EndDrag: function(e) { },
20045
20046     /**
20047      * Fired when we are done dragging the object
20048      * @method endDrag
20049      * @param {Event} e the mouseup event
20050      */
20051     endDrag: function(e) { /* override this */ },
20052
20053     /**
20054      * Code executed immediately before the onMouseDown event
20055      * @method b4MouseDown
20056      * @param {Event} e the mousedown event
20057      * @private
20058      */
20059     b4MouseDown: function(e) {  },
20060
20061     /**
20062      * Event handler that fires when a drag/drop obj gets a mousedown
20063      * @method onMouseDown
20064      * @param {Event} e the mousedown event
20065      */
20066     onMouseDown: function(e) { /* override this */ },
20067
20068     /**
20069      * Event handler that fires when a drag/drop obj gets a mouseup
20070      * @method onMouseUp
20071      * @param {Event} e the mouseup event
20072      */
20073     onMouseUp: function(e) { /* override this */ },
20074
20075     /**
20076      * Override the onAvailable method to do what is needed after the initial
20077      * position was determined.
20078      * @method onAvailable
20079      */
20080     onAvailable: function () {
20081     },
20082
20083     /*
20084      * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
20085      * @type Object
20086      */
20087     defaultPadding : {left:0, right:0, top:0, bottom:0},
20088
20089     /*
20090      * Initializes the drag drop object's constraints to restrict movement to a certain element.
20091  *
20092  * Usage:
20093  <pre><code>
20094  var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
20095                 { dragElId: "existingProxyDiv" });
20096  dd.startDrag = function(){
20097      this.constrainTo("parent-id");
20098  };
20099  </code></pre>
20100  * Or you can initalize it using the {@link Roo.Element} object:
20101  <pre><code>
20102  Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
20103      startDrag : function(){
20104          this.constrainTo("parent-id");
20105      }
20106  });
20107  </code></pre>
20108      * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
20109      * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
20110      * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
20111      * an object containing the sides to pad. For example: {right:10, bottom:10}
20112      * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
20113      */
20114     constrainTo : function(constrainTo, pad, inContent){
20115         if(typeof pad == "number"){
20116             pad = {left: pad, right:pad, top:pad, bottom:pad};
20117         }
20118         pad = pad || this.defaultPadding;
20119         var b = Roo.get(this.getEl()).getBox();
20120         var ce = Roo.get(constrainTo);
20121         var s = ce.getScroll();
20122         var c, cd = ce.dom;
20123         if(cd == document.body){
20124             c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
20125         }else{
20126             xy = ce.getXY();
20127             c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
20128         }
20129
20130
20131         var topSpace = b.y - c.y;
20132         var leftSpace = b.x - c.x;
20133
20134         this.resetConstraints();
20135         this.setXConstraint(leftSpace - (pad.left||0), // left
20136                 c.width - leftSpace - b.width - (pad.right||0) //right
20137         );
20138         this.setYConstraint(topSpace - (pad.top||0), //top
20139                 c.height - topSpace - b.height - (pad.bottom||0) //bottom
20140         );
20141     },
20142
20143     /**
20144      * Returns a reference to the linked element
20145      * @method getEl
20146      * @return {HTMLElement} the html element
20147      */
20148     getEl: function() {
20149         if (!this._domRef) {
20150             this._domRef = Roo.getDom(this.id);
20151         }
20152
20153         return this._domRef;
20154     },
20155
20156     /**
20157      * Returns a reference to the actual element to drag.  By default this is
20158      * the same as the html element, but it can be assigned to another
20159      * element. An example of this can be found in Roo.dd.DDProxy
20160      * @method getDragEl
20161      * @return {HTMLElement} the html element
20162      */
20163     getDragEl: function() {
20164         return Roo.getDom(this.dragElId);
20165     },
20166
20167     /**
20168      * Sets up the DragDrop object.  Must be called in the constructor of any
20169      * Roo.dd.DragDrop subclass
20170      * @method init
20171      * @param id the id of the linked element
20172      * @param {String} sGroup the group of related items
20173      * @param {object} config configuration attributes
20174      */
20175     init: function(id, sGroup, config) {
20176         this.initTarget(id, sGroup, config);
20177         if (!Roo.isTouch) {
20178             Event.on(this.id, "mousedown", this.handleMouseDown, this);
20179         }
20180         Event.on(this.id, "touchstart", this.handleMouseDown, this);
20181         // Event.on(this.id, "selectstart", Event.preventDefault);
20182     },
20183
20184     /**
20185      * Initializes Targeting functionality only... the object does not
20186      * get a mousedown handler.
20187      * @method initTarget
20188      * @param id the id of the linked element
20189      * @param {String} sGroup the group of related items
20190      * @param {object} config configuration attributes
20191      */
20192     initTarget: function(id, sGroup, config) {
20193
20194         // configuration attributes
20195         this.config = config || {};
20196
20197         // create a local reference to the drag and drop manager
20198         this.DDM = Roo.dd.DDM;
20199         // initialize the groups array
20200         this.groups = {};
20201
20202         // assume that we have an element reference instead of an id if the
20203         // parameter is not a string
20204         if (typeof id !== "string") {
20205             id = Roo.id(id);
20206         }
20207
20208         // set the id
20209         this.id = id;
20210
20211         // add to an interaction group
20212         this.addToGroup((sGroup) ? sGroup : "default");
20213
20214         // We don't want to register this as the handle with the manager
20215         // so we just set the id rather than calling the setter.
20216         this.handleElId = id;
20217
20218         // the linked element is the element that gets dragged by default
20219         this.setDragElId(id);
20220
20221         // by default, clicked anchors will not start drag operations.
20222         this.invalidHandleTypes = { A: "A" };
20223         this.invalidHandleIds = {};
20224         this.invalidHandleClasses = [];
20225
20226         this.applyConfig();
20227
20228         this.handleOnAvailable();
20229     },
20230
20231     /**
20232      * Applies the configuration parameters that were passed into the constructor.
20233      * This is supposed to happen at each level through the inheritance chain.  So
20234      * a DDProxy implentation will execute apply config on DDProxy, DD, and
20235      * DragDrop in order to get all of the parameters that are available in
20236      * each object.
20237      * @method applyConfig
20238      */
20239     applyConfig: function() {
20240
20241         // configurable properties:
20242         //    padding, isTarget, maintainOffset, primaryButtonOnly
20243         this.padding           = this.config.padding || [0, 0, 0, 0];
20244         this.isTarget          = (this.config.isTarget !== false);
20245         this.maintainOffset    = (this.config.maintainOffset);
20246         this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
20247
20248     },
20249
20250     /**
20251      * Executed when the linked element is available
20252      * @method handleOnAvailable
20253      * @private
20254      */
20255     handleOnAvailable: function() {
20256         this.available = true;
20257         this.resetConstraints();
20258         this.onAvailable();
20259     },
20260
20261      /**
20262      * Configures the padding for the target zone in px.  Effectively expands
20263      * (or reduces) the virtual object size for targeting calculations.
20264      * Supports css-style shorthand; if only one parameter is passed, all sides
20265      * will have that padding, and if only two are passed, the top and bottom
20266      * will have the first param, the left and right the second.
20267      * @method setPadding
20268      * @param {int} iTop    Top pad
20269      * @param {int} iRight  Right pad
20270      * @param {int} iBot    Bot pad
20271      * @param {int} iLeft   Left pad
20272      */
20273     setPadding: function(iTop, iRight, iBot, iLeft) {
20274         // this.padding = [iLeft, iRight, iTop, iBot];
20275         if (!iRight && 0 !== iRight) {
20276             this.padding = [iTop, iTop, iTop, iTop];
20277         } else if (!iBot && 0 !== iBot) {
20278             this.padding = [iTop, iRight, iTop, iRight];
20279         } else {
20280             this.padding = [iTop, iRight, iBot, iLeft];
20281         }
20282     },
20283
20284     /**
20285      * Stores the initial placement of the linked element.
20286      * @method setInitialPosition
20287      * @param {int} diffX   the X offset, default 0
20288      * @param {int} diffY   the Y offset, default 0
20289      */
20290     setInitPosition: function(diffX, diffY) {
20291         var el = this.getEl();
20292
20293         if (!this.DDM.verifyEl(el)) {
20294             return;
20295         }
20296
20297         var dx = diffX || 0;
20298         var dy = diffY || 0;
20299
20300         var p = Dom.getXY( el );
20301
20302         this.initPageX = p[0] - dx;
20303         this.initPageY = p[1] - dy;
20304
20305         this.lastPageX = p[0];
20306         this.lastPageY = p[1];
20307
20308
20309         this.setStartPosition(p);
20310     },
20311
20312     /**
20313      * Sets the start position of the element.  This is set when the obj
20314      * is initialized, the reset when a drag is started.
20315      * @method setStartPosition
20316      * @param pos current position (from previous lookup)
20317      * @private
20318      */
20319     setStartPosition: function(pos) {
20320         var p = pos || Dom.getXY( this.getEl() );
20321         this.deltaSetXY = null;
20322
20323         this.startPageX = p[0];
20324         this.startPageY = p[1];
20325     },
20326
20327     /**
20328      * Add this instance to a group of related drag/drop objects.  All
20329      * instances belong to at least one group, and can belong to as many
20330      * groups as needed.
20331      * @method addToGroup
20332      * @param sGroup {string} the name of the group
20333      */
20334     addToGroup: function(sGroup) {
20335         this.groups[sGroup] = true;
20336         this.DDM.regDragDrop(this, sGroup);
20337     },
20338
20339     /**
20340      * Remove's this instance from the supplied interaction group
20341      * @method removeFromGroup
20342      * @param {string}  sGroup  The group to drop
20343      */
20344     removeFromGroup: function(sGroup) {
20345         if (this.groups[sGroup]) {
20346             delete this.groups[sGroup];
20347         }
20348
20349         this.DDM.removeDDFromGroup(this, sGroup);
20350     },
20351
20352     /**
20353      * Allows you to specify that an element other than the linked element
20354      * will be moved with the cursor during a drag
20355      * @method setDragElId
20356      * @param id {string} the id of the element that will be used to initiate the drag
20357      */
20358     setDragElId: function(id) {
20359         this.dragElId = id;
20360     },
20361
20362     /**
20363      * Allows you to specify a child of the linked element that should be
20364      * used to initiate the drag operation.  An example of this would be if
20365      * you have a content div with text and links.  Clicking anywhere in the
20366      * content area would normally start the drag operation.  Use this method
20367      * to specify that an element inside of the content div is the element
20368      * that starts the drag operation.
20369      * @method setHandleElId
20370      * @param id {string} the id of the element that will be used to
20371      * initiate the drag.
20372      */
20373     setHandleElId: function(id) {
20374         if (typeof id !== "string") {
20375             id = Roo.id(id);
20376         }
20377         this.handleElId = id;
20378         this.DDM.regHandle(this.id, id);
20379     },
20380
20381     /**
20382      * Allows you to set an element outside of the linked element as a drag
20383      * handle
20384      * @method setOuterHandleElId
20385      * @param id the id of the element that will be used to initiate the drag
20386      */
20387     setOuterHandleElId: function(id) {
20388         if (typeof id !== "string") {
20389             id = Roo.id(id);
20390         }
20391         Event.on(id, "mousedown",
20392                 this.handleMouseDown, this);
20393         this.setHandleElId(id);
20394
20395         this.hasOuterHandles = true;
20396     },
20397
20398     /**
20399      * Remove all drag and drop hooks for this element
20400      * @method unreg
20401      */
20402     unreg: function() {
20403         Event.un(this.id, "mousedown",
20404                 this.handleMouseDown);
20405         Event.un(this.id, "touchstart",
20406                 this.handleMouseDown);
20407         this._domRef = null;
20408         this.DDM._remove(this);
20409     },
20410
20411     destroy : function(){
20412         this.unreg();
20413     },
20414
20415     /**
20416      * Returns true if this instance is locked, or the drag drop mgr is locked
20417      * (meaning that all drag/drop is disabled on the page.)
20418      * @method isLocked
20419      * @return {boolean} true if this obj or all drag/drop is locked, else
20420      * false
20421      */
20422     isLocked: function() {
20423         return (this.DDM.isLocked() || this.locked);
20424     },
20425
20426     /**
20427      * Fired when this object is clicked
20428      * @method handleMouseDown
20429      * @param {Event} e
20430      * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
20431      * @private
20432      */
20433     handleMouseDown: function(e, oDD){
20434      
20435         if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
20436             //Roo.log('not touch/ button !=0');
20437             return;
20438         }
20439         if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
20440             return; // double touch..
20441         }
20442         
20443
20444         if (this.isLocked()) {
20445             //Roo.log('locked');
20446             return;
20447         }
20448
20449         this.DDM.refreshCache(this.groups);
20450 //        Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
20451         var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
20452         if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) )  {
20453             //Roo.log('no outer handes or not over target');
20454                 // do nothing.
20455         } else {
20456 //            Roo.log('check validator');
20457             if (this.clickValidator(e)) {
20458 //                Roo.log('validate success');
20459                 // set the initial element position
20460                 this.setStartPosition();
20461
20462
20463                 this.b4MouseDown(e);
20464                 this.onMouseDown(e);
20465
20466                 this.DDM.handleMouseDown(e, this);
20467
20468                 this.DDM.stopEvent(e);
20469             } else {
20470
20471
20472             }
20473         }
20474     },
20475
20476     clickValidator: function(e) {
20477         var target = e.getTarget();
20478         return ( this.isValidHandleChild(target) &&
20479                     (this.id == this.handleElId ||
20480                         this.DDM.handleWasClicked(target, this.id)) );
20481     },
20482
20483     /**
20484      * Allows you to specify a tag name that should not start a drag operation
20485      * when clicked.  This is designed to facilitate embedding links within a
20486      * drag handle that do something other than start the drag.
20487      * @method addInvalidHandleType
20488      * @param {string} tagName the type of element to exclude
20489      */
20490     addInvalidHandleType: function(tagName) {
20491         var type = tagName.toUpperCase();
20492         this.invalidHandleTypes[type] = type;
20493     },
20494
20495     /**
20496      * Lets you to specify an element id for a child of a drag handle
20497      * that should not initiate a drag
20498      * @method addInvalidHandleId
20499      * @param {string} id the element id of the element you wish to ignore
20500      */
20501     addInvalidHandleId: function(id) {
20502         if (typeof id !== "string") {
20503             id = Roo.id(id);
20504         }
20505         this.invalidHandleIds[id] = id;
20506     },
20507
20508     /**
20509      * Lets you specify a css class of elements that will not initiate a drag
20510      * @method addInvalidHandleClass
20511      * @param {string} cssClass the class of the elements you wish to ignore
20512      */
20513     addInvalidHandleClass: function(cssClass) {
20514         this.invalidHandleClasses.push(cssClass);
20515     },
20516
20517     /**
20518      * Unsets an excluded tag name set by addInvalidHandleType
20519      * @method removeInvalidHandleType
20520      * @param {string} tagName the type of element to unexclude
20521      */
20522     removeInvalidHandleType: function(tagName) {
20523         var type = tagName.toUpperCase();
20524         // this.invalidHandleTypes[type] = null;
20525         delete this.invalidHandleTypes[type];
20526     },
20527
20528     /**
20529      * Unsets an invalid handle id
20530      * @method removeInvalidHandleId
20531      * @param {string} id the id of the element to re-enable
20532      */
20533     removeInvalidHandleId: function(id) {
20534         if (typeof id !== "string") {
20535             id = Roo.id(id);
20536         }
20537         delete this.invalidHandleIds[id];
20538     },
20539
20540     /**
20541      * Unsets an invalid css class
20542      * @method removeInvalidHandleClass
20543      * @param {string} cssClass the class of the element(s) you wish to
20544      * re-enable
20545      */
20546     removeInvalidHandleClass: function(cssClass) {
20547         for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
20548             if (this.invalidHandleClasses[i] == cssClass) {
20549                 delete this.invalidHandleClasses[i];
20550             }
20551         }
20552     },
20553
20554     /**
20555      * Checks the tag exclusion list to see if this click should be ignored
20556      * @method isValidHandleChild
20557      * @param {HTMLElement} node the HTMLElement to evaluate
20558      * @return {boolean} true if this is a valid tag type, false if not
20559      */
20560     isValidHandleChild: function(node) {
20561
20562         var valid = true;
20563         // var n = (node.nodeName == "#text") ? node.parentNode : node;
20564         var nodeName;
20565         try {
20566             nodeName = node.nodeName.toUpperCase();
20567         } catch(e) {
20568             nodeName = node.nodeName;
20569         }
20570         valid = valid && !this.invalidHandleTypes[nodeName];
20571         valid = valid && !this.invalidHandleIds[node.id];
20572
20573         for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
20574             valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
20575         }
20576
20577
20578         return valid;
20579
20580     },
20581
20582     /**
20583      * Create the array of horizontal tick marks if an interval was specified
20584      * in setXConstraint().
20585      * @method setXTicks
20586      * @private
20587      */
20588     setXTicks: function(iStartX, iTickSize) {
20589         this.xTicks = [];
20590         this.xTickSize = iTickSize;
20591
20592         var tickMap = {};
20593
20594         for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
20595             if (!tickMap[i]) {
20596                 this.xTicks[this.xTicks.length] = i;
20597                 tickMap[i] = true;
20598             }
20599         }
20600
20601         for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
20602             if (!tickMap[i]) {
20603                 this.xTicks[this.xTicks.length] = i;
20604                 tickMap[i] = true;
20605             }
20606         }
20607
20608         this.xTicks.sort(this.DDM.numericSort) ;
20609     },
20610
20611     /**
20612      * Create the array of vertical tick marks if an interval was specified in
20613      * setYConstraint().
20614      * @method setYTicks
20615      * @private
20616      */
20617     setYTicks: function(iStartY, iTickSize) {
20618         this.yTicks = [];
20619         this.yTickSize = iTickSize;
20620
20621         var tickMap = {};
20622
20623         for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
20624             if (!tickMap[i]) {
20625                 this.yTicks[this.yTicks.length] = i;
20626                 tickMap[i] = true;
20627             }
20628         }
20629
20630         for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
20631             if (!tickMap[i]) {
20632                 this.yTicks[this.yTicks.length] = i;
20633                 tickMap[i] = true;
20634             }
20635         }
20636
20637         this.yTicks.sort(this.DDM.numericSort) ;
20638     },
20639
20640     /**
20641      * By default, the element can be dragged any place on the screen.  Use
20642      * this method to limit the horizontal travel of the element.  Pass in
20643      * 0,0 for the parameters if you want to lock the drag to the y axis.
20644      * @method setXConstraint
20645      * @param {int} iLeft the number of pixels the element can move to the left
20646      * @param {int} iRight the number of pixels the element can move to the
20647      * right
20648      * @param {int} iTickSize optional parameter for specifying that the
20649      * element
20650      * should move iTickSize pixels at a time.
20651      */
20652     setXConstraint: function(iLeft, iRight, iTickSize) {
20653         this.leftConstraint = iLeft;
20654         this.rightConstraint = iRight;
20655
20656         this.minX = this.initPageX - iLeft;
20657         this.maxX = this.initPageX + iRight;
20658         if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
20659
20660         this.constrainX = true;
20661     },
20662
20663     /**
20664      * Clears any constraints applied to this instance.  Also clears ticks
20665      * since they can't exist independent of a constraint at this time.
20666      * @method clearConstraints
20667      */
20668     clearConstraints: function() {
20669         this.constrainX = false;
20670         this.constrainY = false;
20671         this.clearTicks();
20672     },
20673
20674     /**
20675      * Clears any tick interval defined for this instance
20676      * @method clearTicks
20677      */
20678     clearTicks: function() {
20679         this.xTicks = null;
20680         this.yTicks = null;
20681         this.xTickSize = 0;
20682         this.yTickSize = 0;
20683     },
20684
20685     /**
20686      * By default, the element can be dragged any place on the screen.  Set
20687      * this to limit the vertical travel of the element.  Pass in 0,0 for the
20688      * parameters if you want to lock the drag to the x axis.
20689      * @method setYConstraint
20690      * @param {int} iUp the number of pixels the element can move up
20691      * @param {int} iDown the number of pixels the element can move down
20692      * @param {int} iTickSize optional parameter for specifying that the
20693      * element should move iTickSize pixels at a time.
20694      */
20695     setYConstraint: function(iUp, iDown, iTickSize) {
20696         this.topConstraint = iUp;
20697         this.bottomConstraint = iDown;
20698
20699         this.minY = this.initPageY - iUp;
20700         this.maxY = this.initPageY + iDown;
20701         if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
20702
20703         this.constrainY = true;
20704
20705     },
20706
20707     /**
20708      * resetConstraints must be called if you manually reposition a dd element.
20709      * @method resetConstraints
20710      * @param {boolean} maintainOffset
20711      */
20712     resetConstraints: function() {
20713
20714
20715         // Maintain offsets if necessary
20716         if (this.initPageX || this.initPageX === 0) {
20717             // figure out how much this thing has moved
20718             var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
20719             var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
20720
20721             this.setInitPosition(dx, dy);
20722
20723         // This is the first time we have detected the element's position
20724         } else {
20725             this.setInitPosition();
20726         }
20727
20728         if (this.constrainX) {
20729             this.setXConstraint( this.leftConstraint,
20730                                  this.rightConstraint,
20731                                  this.xTickSize        );
20732         }
20733
20734         if (this.constrainY) {
20735             this.setYConstraint( this.topConstraint,
20736                                  this.bottomConstraint,
20737                                  this.yTickSize         );
20738         }
20739     },
20740
20741     /**
20742      * Normally the drag element is moved pixel by pixel, but we can specify
20743      * that it move a number of pixels at a time.  This method resolves the
20744      * location when we have it set up like this.
20745      * @method getTick
20746      * @param {int} val where we want to place the object
20747      * @param {int[]} tickArray sorted array of valid points
20748      * @return {int} the closest tick
20749      * @private
20750      */
20751     getTick: function(val, tickArray) {
20752
20753         if (!tickArray) {
20754             // If tick interval is not defined, it is effectively 1 pixel,
20755             // so we return the value passed to us.
20756             return val;
20757         } else if (tickArray[0] >= val) {
20758             // The value is lower than the first tick, so we return the first
20759             // tick.
20760             return tickArray[0];
20761         } else {
20762             for (var i=0, len=tickArray.length; i<len; ++i) {
20763                 var next = i + 1;
20764                 if (tickArray[next] && tickArray[next] >= val) {
20765                     var diff1 = val - tickArray[i];
20766                     var diff2 = tickArray[next] - val;
20767                     return (diff2 > diff1) ? tickArray[i] : tickArray[next];
20768                 }
20769             }
20770
20771             // The value is larger than the last tick, so we return the last
20772             // tick.
20773             return tickArray[tickArray.length - 1];
20774         }
20775     },
20776
20777     /**
20778      * toString method
20779      * @method toString
20780      * @return {string} string representation of the dd obj
20781      */
20782     toString: function() {
20783         return ("DragDrop " + this.id);
20784     }
20785
20786 });
20787
20788 })();
20789 /*
20790  * Based on:
20791  * Ext JS Library 1.1.1
20792  * Copyright(c) 2006-2007, Ext JS, LLC.
20793  *
20794  * Originally Released Under LGPL - original licence link has changed is not relivant.
20795  *
20796  * Fork - LGPL
20797  * <script type="text/javascript">
20798  */
20799
20800
20801 /**
20802  * The drag and drop utility provides a framework for building drag and drop
20803  * applications.  In addition to enabling drag and drop for specific elements,
20804  * the drag and drop elements are tracked by the manager class, and the
20805  * interactions between the various elements are tracked during the drag and
20806  * the implementing code is notified about these important moments.
20807  */
20808
20809 // Only load the library once.  Rewriting the manager class would orphan
20810 // existing drag and drop instances.
20811 if (!Roo.dd.DragDropMgr) {
20812
20813 /**
20814  * @class Roo.dd.DragDropMgr
20815  * DragDropMgr is a singleton that tracks the element interaction for
20816  * all DragDrop items in the window.  Generally, you will not call
20817  * this class directly, but it does have helper methods that could
20818  * be useful in your DragDrop implementations.
20819  * @static
20820  */
20821 Roo.dd.DragDropMgr = function() {
20822
20823     var Event = Roo.EventManager;
20824
20825     return {
20826
20827         /**
20828          * Two dimensional Array of registered DragDrop objects.  The first
20829          * dimension is the DragDrop item group, the second the DragDrop
20830          * object.
20831          * @property ids
20832          * @type {string: string}
20833          * @private
20834          * @static
20835          */
20836         ids: {},
20837
20838         /**
20839          * Array of element ids defined as drag handles.  Used to determine
20840          * if the element that generated the mousedown event is actually the
20841          * handle and not the html element itself.
20842          * @property handleIds
20843          * @type {string: string}
20844          * @private
20845          * @static
20846          */
20847         handleIds: {},
20848
20849         /**
20850          * the DragDrop object that is currently being dragged
20851          * @property dragCurrent
20852          * @type DragDrop
20853          * @private
20854          * @static
20855          **/
20856         dragCurrent: null,
20857
20858         /**
20859          * the DragDrop object(s) that are being hovered over
20860          * @property dragOvers
20861          * @type Array
20862          * @private
20863          * @static
20864          */
20865         dragOvers: {},
20866
20867         /**
20868          * the X distance between the cursor and the object being dragged
20869          * @property deltaX
20870          * @type int
20871          * @private
20872          * @static
20873          */
20874         deltaX: 0,
20875
20876         /**
20877          * the Y distance between the cursor and the object being dragged
20878          * @property deltaY
20879          * @type int
20880          * @private
20881          * @static
20882          */
20883         deltaY: 0,
20884
20885         /**
20886          * Flag to determine if we should prevent the default behavior of the
20887          * events we define. By default this is true, but this can be set to
20888          * false if you need the default behavior (not recommended)
20889          * @property preventDefault
20890          * @type boolean
20891          * @static
20892          */
20893         preventDefault: true,
20894
20895         /**
20896          * Flag to determine if we should stop the propagation of the events
20897          * we generate. This is true by default but you may want to set it to
20898          * false if the html element contains other features that require the
20899          * mouse click.
20900          * @property stopPropagation
20901          * @type boolean
20902          * @static
20903          */
20904         stopPropagation: true,
20905
20906         /**
20907          * Internal flag that is set to true when drag and drop has been
20908          * intialized
20909          * @property initialized
20910          * @private
20911          * @static
20912          */
20913         initalized: false,
20914
20915         /**
20916          * All drag and drop can be disabled.
20917          * @property locked
20918          * @private
20919          * @static
20920          */
20921         locked: false,
20922
20923         /**
20924          * Called the first time an element is registered.
20925          * @method init
20926          * @private
20927          * @static
20928          */
20929         init: function() {
20930             this.initialized = true;
20931         },
20932
20933         /**
20934          * In point mode, drag and drop interaction is defined by the
20935          * location of the cursor during the drag/drop
20936          * @property POINT
20937          * @type int
20938          * @static
20939          */
20940         POINT: 0,
20941
20942         /**
20943          * In intersect mode, drag and drop interactio nis defined by the
20944          * overlap of two or more drag and drop objects.
20945          * @property INTERSECT
20946          * @type int
20947          * @static
20948          */
20949         INTERSECT: 1,
20950
20951         /**
20952          * The current drag and drop mode.  Default: POINT
20953          * @property mode
20954          * @type int
20955          * @static
20956          */
20957         mode: 0,
20958
20959         /**
20960          * Runs method on all drag and drop objects
20961          * @method _execOnAll
20962          * @private
20963          * @static
20964          */
20965         _execOnAll: function(sMethod, args) {
20966             for (var i in this.ids) {
20967                 for (var j in this.ids[i]) {
20968                     var oDD = this.ids[i][j];
20969                     if (! this.isTypeOfDD(oDD)) {
20970                         continue;
20971                     }
20972                     oDD[sMethod].apply(oDD, args);
20973                 }
20974             }
20975         },
20976
20977         /**
20978          * Drag and drop initialization.  Sets up the global event handlers
20979          * @method _onLoad
20980          * @private
20981          * @static
20982          */
20983         _onLoad: function() {
20984
20985             this.init();
20986
20987             if (!Roo.isTouch) {
20988                 Event.on(document, "mouseup",   this.handleMouseUp, this, true);
20989                 Event.on(document, "mousemove", this.handleMouseMove, this, true);
20990             }
20991             Event.on(document, "touchend",   this.handleMouseUp, this, true);
20992             Event.on(document, "touchmove", this.handleMouseMove, this, true);
20993             
20994             Event.on(window,   "unload",    this._onUnload, this, true);
20995             Event.on(window,   "resize",    this._onResize, this, true);
20996             // Event.on(window,   "mouseout",    this._test);
20997
20998         },
20999
21000         /**
21001          * Reset constraints on all drag and drop objs
21002          * @method _onResize
21003          * @private
21004          * @static
21005          */
21006         _onResize: function(e) {
21007             this._execOnAll("resetConstraints", []);
21008         },
21009
21010         /**
21011          * Lock all drag and drop functionality
21012          * @method lock
21013          * @static
21014          */
21015         lock: function() { this.locked = true; },
21016
21017         /**
21018          * Unlock all drag and drop functionality
21019          * @method unlock
21020          * @static
21021          */
21022         unlock: function() { this.locked = false; },
21023
21024         /**
21025          * Is drag and drop locked?
21026          * @method isLocked
21027          * @return {boolean} True if drag and drop is locked, false otherwise.
21028          * @static
21029          */
21030         isLocked: function() { return this.locked; },
21031
21032         /**
21033          * Location cache that is set for all drag drop objects when a drag is
21034          * initiated, cleared when the drag is finished.
21035          * @property locationCache
21036          * @private
21037          * @static
21038          */
21039         locationCache: {},
21040
21041         /**
21042          * Set useCache to false if you want to force object the lookup of each
21043          * drag and drop linked element constantly during a drag.
21044          * @property useCache
21045          * @type boolean
21046          * @static
21047          */
21048         useCache: true,
21049
21050         /**
21051          * The number of pixels that the mouse needs to move after the
21052          * mousedown before the drag is initiated.  Default=3;
21053          * @property clickPixelThresh
21054          * @type int
21055          * @static
21056          */
21057         clickPixelThresh: 3,
21058
21059         /**
21060          * The number of milliseconds after the mousedown event to initiate the
21061          * drag if we don't get a mouseup event. Default=1000
21062          * @property clickTimeThresh
21063          * @type int
21064          * @static
21065          */
21066         clickTimeThresh: 350,
21067
21068         /**
21069          * Flag that indicates that either the drag pixel threshold or the
21070          * mousdown time threshold has been met
21071          * @property dragThreshMet
21072          * @type boolean
21073          * @private
21074          * @static
21075          */
21076         dragThreshMet: false,
21077
21078         /**
21079          * Timeout used for the click time threshold
21080          * @property clickTimeout
21081          * @type Object
21082          * @private
21083          * @static
21084          */
21085         clickTimeout: null,
21086
21087         /**
21088          * The X position of the mousedown event stored for later use when a
21089          * drag threshold is met.
21090          * @property startX
21091          * @type int
21092          * @private
21093          * @static
21094          */
21095         startX: 0,
21096
21097         /**
21098          * The Y position of the mousedown event stored for later use when a
21099          * drag threshold is met.
21100          * @property startY
21101          * @type int
21102          * @private
21103          * @static
21104          */
21105         startY: 0,
21106
21107         /**
21108          * Each DragDrop instance must be registered with the DragDropMgr.
21109          * This is executed in DragDrop.init()
21110          * @method regDragDrop
21111          * @param {DragDrop} oDD the DragDrop object to register
21112          * @param {String} sGroup the name of the group this element belongs to
21113          * @static
21114          */
21115         regDragDrop: function(oDD, sGroup) {
21116             if (!this.initialized) { this.init(); }
21117
21118             if (!this.ids[sGroup]) {
21119                 this.ids[sGroup] = {};
21120             }
21121             this.ids[sGroup][oDD.id] = oDD;
21122         },
21123
21124         /**
21125          * Removes the supplied dd instance from the supplied group. Executed
21126          * by DragDrop.removeFromGroup, so don't call this function directly.
21127          * @method removeDDFromGroup
21128          * @private
21129          * @static
21130          */
21131         removeDDFromGroup: function(oDD, sGroup) {
21132             if (!this.ids[sGroup]) {
21133                 this.ids[sGroup] = {};
21134             }
21135
21136             var obj = this.ids[sGroup];
21137             if (obj && obj[oDD.id]) {
21138                 delete obj[oDD.id];
21139             }
21140         },
21141
21142         /**
21143          * Unregisters a drag and drop item.  This is executed in
21144          * DragDrop.unreg, use that method instead of calling this directly.
21145          * @method _remove
21146          * @private
21147          * @static
21148          */
21149         _remove: function(oDD) {
21150             for (var g in oDD.groups) {
21151                 if (g && this.ids[g][oDD.id]) {
21152                     delete this.ids[g][oDD.id];
21153                 }
21154             }
21155             delete this.handleIds[oDD.id];
21156         },
21157
21158         /**
21159          * Each DragDrop handle element must be registered.  This is done
21160          * automatically when executing DragDrop.setHandleElId()
21161          * @method regHandle
21162          * @param {String} sDDId the DragDrop id this element is a handle for
21163          * @param {String} sHandleId the id of the element that is the drag
21164          * handle
21165          * @static
21166          */
21167         regHandle: function(sDDId, sHandleId) {
21168             if (!this.handleIds[sDDId]) {
21169                 this.handleIds[sDDId] = {};
21170             }
21171             this.handleIds[sDDId][sHandleId] = sHandleId;
21172         },
21173
21174         /**
21175          * Utility function to determine if a given element has been
21176          * registered as a drag drop item.
21177          * @method isDragDrop
21178          * @param {String} id the element id to check
21179          * @return {boolean} true if this element is a DragDrop item,
21180          * false otherwise
21181          * @static
21182          */
21183         isDragDrop: function(id) {
21184             return ( this.getDDById(id) ) ? true : false;
21185         },
21186
21187         /**
21188          * Returns the drag and drop instances that are in all groups the
21189          * passed in instance belongs to.
21190          * @method getRelated
21191          * @param {DragDrop} p_oDD the obj to get related data for
21192          * @param {boolean} bTargetsOnly if true, only return targetable objs
21193          * @return {DragDrop[]} the related instances
21194          * @static
21195          */
21196         getRelated: function(p_oDD, bTargetsOnly) {
21197             var oDDs = [];
21198             for (var i in p_oDD.groups) {
21199                 for (j in this.ids[i]) {
21200                     var dd = this.ids[i][j];
21201                     if (! this.isTypeOfDD(dd)) {
21202                         continue;
21203                     }
21204                     if (!bTargetsOnly || dd.isTarget) {
21205                         oDDs[oDDs.length] = dd;
21206                     }
21207                 }
21208             }
21209
21210             return oDDs;
21211         },
21212
21213         /**
21214          * Returns true if the specified dd target is a legal target for
21215          * the specifice drag obj
21216          * @method isLegalTarget
21217          * @param {DragDrop} the drag obj
21218          * @param {DragDrop} the target
21219          * @return {boolean} true if the target is a legal target for the
21220          * dd obj
21221          * @static
21222          */
21223         isLegalTarget: function (oDD, oTargetDD) {
21224             var targets = this.getRelated(oDD, true);
21225             for (var i=0, len=targets.length;i<len;++i) {
21226                 if (targets[i].id == oTargetDD.id) {
21227                     return true;
21228                 }
21229             }
21230
21231             return false;
21232         },
21233
21234         /**
21235          * My goal is to be able to transparently determine if an object is
21236          * typeof DragDrop, and the exact subclass of DragDrop.  typeof
21237          * returns "object", oDD.constructor.toString() always returns
21238          * "DragDrop" and not the name of the subclass.  So for now it just
21239          * evaluates a well-known variable in DragDrop.
21240          * @method isTypeOfDD
21241          * @param {Object} the object to evaluate
21242          * @return {boolean} true if typeof oDD = DragDrop
21243          * @static
21244          */
21245         isTypeOfDD: function (oDD) {
21246             return (oDD && oDD.__ygDragDrop);
21247         },
21248
21249         /**
21250          * Utility function to determine if a given element has been
21251          * registered as a drag drop handle for the given Drag Drop object.
21252          * @method isHandle
21253          * @param {String} id the element id to check
21254          * @return {boolean} true if this element is a DragDrop handle, false
21255          * otherwise
21256          * @static
21257          */
21258         isHandle: function(sDDId, sHandleId) {
21259             return ( this.handleIds[sDDId] &&
21260                             this.handleIds[sDDId][sHandleId] );
21261         },
21262
21263         /**
21264          * Returns the DragDrop instance for a given id
21265          * @method getDDById
21266          * @param {String} id the id of the DragDrop object
21267          * @return {DragDrop} the drag drop object, null if it is not found
21268          * @static
21269          */
21270         getDDById: function(id) {
21271             for (var i in this.ids) {
21272                 if (this.ids[i][id]) {
21273                     return this.ids[i][id];
21274                 }
21275             }
21276             return null;
21277         },
21278
21279         /**
21280          * Fired after a registered DragDrop object gets the mousedown event.
21281          * Sets up the events required to track the object being dragged
21282          * @method handleMouseDown
21283          * @param {Event} e the event
21284          * @param oDD the DragDrop object being dragged
21285          * @private
21286          * @static
21287          */
21288         handleMouseDown: function(e, oDD) {
21289             if(Roo.QuickTips){
21290                 Roo.QuickTips.disable();
21291             }
21292             this.currentTarget = e.getTarget();
21293
21294             this.dragCurrent = oDD;
21295
21296             var el = oDD.getEl();
21297
21298             // track start position
21299             this.startX = e.getPageX();
21300             this.startY = e.getPageY();
21301
21302             this.deltaX = this.startX - el.offsetLeft;
21303             this.deltaY = this.startY - el.offsetTop;
21304
21305             this.dragThreshMet = false;
21306
21307             this.clickTimeout = setTimeout(
21308                     function() {
21309                         var DDM = Roo.dd.DDM;
21310                         DDM.startDrag(DDM.startX, DDM.startY);
21311                     },
21312                     this.clickTimeThresh );
21313         },
21314
21315         /**
21316          * Fired when either the drag pixel threshol or the mousedown hold
21317          * time threshold has been met.
21318          * @method startDrag
21319          * @param x {int} the X position of the original mousedown
21320          * @param y {int} the Y position of the original mousedown
21321          * @static
21322          */
21323         startDrag: function(x, y) {
21324             clearTimeout(this.clickTimeout);
21325             if (this.dragCurrent) {
21326                 this.dragCurrent.b4StartDrag(x, y);
21327                 this.dragCurrent.startDrag(x, y);
21328             }
21329             this.dragThreshMet = true;
21330         },
21331
21332         /**
21333          * Internal function to handle the mouseup event.  Will be invoked
21334          * from the context of the document.
21335          * @method handleMouseUp
21336          * @param {Event} e the event
21337          * @private
21338          * @static
21339          */
21340         handleMouseUp: function(e) {
21341
21342             if(Roo.QuickTips){
21343                 Roo.QuickTips.enable();
21344             }
21345             if (! this.dragCurrent) {
21346                 return;
21347             }
21348
21349             clearTimeout(this.clickTimeout);
21350
21351             if (this.dragThreshMet) {
21352                 this.fireEvents(e, true);
21353             } else {
21354             }
21355
21356             this.stopDrag(e);
21357
21358             this.stopEvent(e);
21359         },
21360
21361         /**
21362          * Utility to stop event propagation and event default, if these
21363          * features are turned on.
21364          * @method stopEvent
21365          * @param {Event} e the event as returned by this.getEvent()
21366          * @static
21367          */
21368         stopEvent: function(e){
21369             if(this.stopPropagation) {
21370                 e.stopPropagation();
21371             }
21372
21373             if (this.preventDefault) {
21374                 e.preventDefault();
21375             }
21376         },
21377
21378         /**
21379          * Internal function to clean up event handlers after the drag
21380          * operation is complete
21381          * @method stopDrag
21382          * @param {Event} e the event
21383          * @private
21384          * @static
21385          */
21386         stopDrag: function(e) {
21387             // Fire the drag end event for the item that was dragged
21388             if (this.dragCurrent) {
21389                 if (this.dragThreshMet) {
21390                     this.dragCurrent.b4EndDrag(e);
21391                     this.dragCurrent.endDrag(e);
21392                 }
21393
21394                 this.dragCurrent.onMouseUp(e);
21395             }
21396
21397             this.dragCurrent = null;
21398             this.dragOvers = {};
21399         },
21400
21401         /**
21402          * Internal function to handle the mousemove event.  Will be invoked
21403          * from the context of the html element.
21404          *
21405          * @TODO figure out what we can do about mouse events lost when the
21406          * user drags objects beyond the window boundary.  Currently we can
21407          * detect this in internet explorer by verifying that the mouse is
21408          * down during the mousemove event.  Firefox doesn't give us the
21409          * button state on the mousemove event.
21410          * @method handleMouseMove
21411          * @param {Event} e the event
21412          * @private
21413          * @static
21414          */
21415         handleMouseMove: function(e) {
21416             if (! this.dragCurrent) {
21417                 return true;
21418             }
21419
21420             // var button = e.which || e.button;
21421
21422             // check for IE mouseup outside of page boundary
21423             if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
21424                 this.stopEvent(e);
21425                 return this.handleMouseUp(e);
21426             }
21427
21428             if (!this.dragThreshMet) {
21429                 var diffX = Math.abs(this.startX - e.getPageX());
21430                 var diffY = Math.abs(this.startY - e.getPageY());
21431                 if (diffX > this.clickPixelThresh ||
21432                             diffY > this.clickPixelThresh) {
21433                     this.startDrag(this.startX, this.startY);
21434                 }
21435             }
21436
21437             if (this.dragThreshMet) {
21438                 this.dragCurrent.b4Drag(e);
21439                 this.dragCurrent.onDrag(e);
21440                 if(!this.dragCurrent.moveOnly){
21441                     this.fireEvents(e, false);
21442                 }
21443             }
21444
21445             this.stopEvent(e);
21446
21447             return true;
21448         },
21449
21450         /**
21451          * Iterates over all of the DragDrop elements to find ones we are
21452          * hovering over or dropping on
21453          * @method fireEvents
21454          * @param {Event} e the event
21455          * @param {boolean} isDrop is this a drop op or a mouseover op?
21456          * @private
21457          * @static
21458          */
21459         fireEvents: function(e, isDrop) {
21460             var dc = this.dragCurrent;
21461
21462             // If the user did the mouse up outside of the window, we could
21463             // get here even though we have ended the drag.
21464             if (!dc || dc.isLocked()) {
21465                 return;
21466             }
21467
21468             var pt = e.getPoint();
21469
21470             // cache the previous dragOver array
21471             var oldOvers = [];
21472
21473             var outEvts   = [];
21474             var overEvts  = [];
21475             var dropEvts  = [];
21476             var enterEvts = [];
21477
21478             // Check to see if the object(s) we were hovering over is no longer
21479             // being hovered over so we can fire the onDragOut event
21480             for (var i in this.dragOvers) {
21481
21482                 var ddo = this.dragOvers[i];
21483
21484                 if (! this.isTypeOfDD(ddo)) {
21485                     continue;
21486                 }
21487
21488                 if (! this.isOverTarget(pt, ddo, this.mode)) {
21489                     outEvts.push( ddo );
21490                 }
21491
21492                 oldOvers[i] = true;
21493                 delete this.dragOvers[i];
21494             }
21495
21496             for (var sGroup in dc.groups) {
21497
21498                 if ("string" != typeof sGroup) {
21499                     continue;
21500                 }
21501
21502                 for (i in this.ids[sGroup]) {
21503                     var oDD = this.ids[sGroup][i];
21504                     if (! this.isTypeOfDD(oDD)) {
21505                         continue;
21506                     }
21507
21508                     if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
21509                         if (this.isOverTarget(pt, oDD, this.mode)) {
21510                             // look for drop interactions
21511                             if (isDrop) {
21512                                 dropEvts.push( oDD );
21513                             // look for drag enter and drag over interactions
21514                             } else {
21515
21516                                 // initial drag over: dragEnter fires
21517                                 if (!oldOvers[oDD.id]) {
21518                                     enterEvts.push( oDD );
21519                                 // subsequent drag overs: dragOver fires
21520                                 } else {
21521                                     overEvts.push( oDD );
21522                                 }
21523
21524                                 this.dragOvers[oDD.id] = oDD;
21525                             }
21526                         }
21527                     }
21528                 }
21529             }
21530
21531             if (this.mode) {
21532                 if (outEvts.length) {
21533                     dc.b4DragOut(e, outEvts);
21534                     dc.onDragOut(e, outEvts);
21535                 }
21536
21537                 if (enterEvts.length) {
21538                     dc.onDragEnter(e, enterEvts);
21539                 }
21540
21541                 if (overEvts.length) {
21542                     dc.b4DragOver(e, overEvts);
21543                     dc.onDragOver(e, overEvts);
21544                 }
21545
21546                 if (dropEvts.length) {
21547                     dc.b4DragDrop(e, dropEvts);
21548                     dc.onDragDrop(e, dropEvts);
21549                 }
21550
21551             } else {
21552                 // fire dragout events
21553                 var len = 0;
21554                 for (i=0, len=outEvts.length; i<len; ++i) {
21555                     dc.b4DragOut(e, outEvts[i].id);
21556                     dc.onDragOut(e, outEvts[i].id);
21557                 }
21558
21559                 // fire enter events
21560                 for (i=0,len=enterEvts.length; i<len; ++i) {
21561                     // dc.b4DragEnter(e, oDD.id);
21562                     dc.onDragEnter(e, enterEvts[i].id);
21563                 }
21564
21565                 // fire over events
21566                 for (i=0,len=overEvts.length; i<len; ++i) {
21567                     dc.b4DragOver(e, overEvts[i].id);
21568                     dc.onDragOver(e, overEvts[i].id);
21569                 }
21570
21571                 // fire drop events
21572                 for (i=0, len=dropEvts.length; i<len; ++i) {
21573                     dc.b4DragDrop(e, dropEvts[i].id);
21574                     dc.onDragDrop(e, dropEvts[i].id);
21575                 }
21576
21577             }
21578
21579             // notify about a drop that did not find a target
21580             if (isDrop && !dropEvts.length) {
21581                 dc.onInvalidDrop(e);
21582             }
21583
21584         },
21585
21586         /**
21587          * Helper function for getting the best match from the list of drag
21588          * and drop objects returned by the drag and drop events when we are
21589          * in INTERSECT mode.  It returns either the first object that the
21590          * cursor is over, or the object that has the greatest overlap with
21591          * the dragged element.
21592          * @method getBestMatch
21593          * @param  {DragDrop[]} dds The array of drag and drop objects
21594          * targeted
21595          * @return {DragDrop}       The best single match
21596          * @static
21597          */
21598         getBestMatch: function(dds) {
21599             var winner = null;
21600             // Return null if the input is not what we expect
21601             //if (!dds || !dds.length || dds.length == 0) {
21602                // winner = null;
21603             // If there is only one item, it wins
21604             //} else if (dds.length == 1) {
21605
21606             var len = dds.length;
21607
21608             if (len == 1) {
21609                 winner = dds[0];
21610             } else {
21611                 // Loop through the targeted items
21612                 for (var i=0; i<len; ++i) {
21613                     var dd = dds[i];
21614                     // If the cursor is over the object, it wins.  If the
21615                     // cursor is over multiple matches, the first one we come
21616                     // to wins.
21617                     if (dd.cursorIsOver) {
21618                         winner = dd;
21619                         break;
21620                     // Otherwise the object with the most overlap wins
21621                     } else {
21622                         if (!winner ||
21623                             winner.overlap.getArea() < dd.overlap.getArea()) {
21624                             winner = dd;
21625                         }
21626                     }
21627                 }
21628             }
21629
21630             return winner;
21631         },
21632
21633         /**
21634          * Refreshes the cache of the top-left and bottom-right points of the
21635          * drag and drop objects in the specified group(s).  This is in the
21636          * format that is stored in the drag and drop instance, so typical
21637          * usage is:
21638          * <code>
21639          * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
21640          * </code>
21641          * Alternatively:
21642          * <code>
21643          * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
21644          * </code>
21645          * @TODO this really should be an indexed array.  Alternatively this
21646          * method could accept both.
21647          * @method refreshCache
21648          * @param {Object} groups an associative array of groups to refresh
21649          * @static
21650          */
21651         refreshCache: function(groups) {
21652             for (var sGroup in groups) {
21653                 if ("string" != typeof sGroup) {
21654                     continue;
21655                 }
21656                 for (var i in this.ids[sGroup]) {
21657                     var oDD = this.ids[sGroup][i];
21658
21659                     if (this.isTypeOfDD(oDD)) {
21660                     // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
21661                         var loc = this.getLocation(oDD);
21662                         if (loc) {
21663                             this.locationCache[oDD.id] = loc;
21664                         } else {
21665                             delete this.locationCache[oDD.id];
21666                             // this will unregister the drag and drop object if
21667                             // the element is not in a usable state
21668                             // oDD.unreg();
21669                         }
21670                     }
21671                 }
21672             }
21673         },
21674
21675         /**
21676          * This checks to make sure an element exists and is in the DOM.  The
21677          * main purpose is to handle cases where innerHTML is used to remove
21678          * drag and drop objects from the DOM.  IE provides an 'unspecified
21679          * error' when trying to access the offsetParent of such an element
21680          * @method verifyEl
21681          * @param {HTMLElement} el the element to check
21682          * @return {boolean} true if the element looks usable
21683          * @static
21684          */
21685         verifyEl: function(el) {
21686             if (el) {
21687                 var parent;
21688                 if(Roo.isIE){
21689                     try{
21690                         parent = el.offsetParent;
21691                     }catch(e){}
21692                 }else{
21693                     parent = el.offsetParent;
21694                 }
21695                 if (parent) {
21696                     return true;
21697                 }
21698             }
21699
21700             return false;
21701         },
21702
21703         /**
21704          * Returns a Region object containing the drag and drop element's position
21705          * and size, including the padding configured for it
21706          * @method getLocation
21707          * @param {DragDrop} oDD the drag and drop object to get the
21708          *                       location for
21709          * @return {Roo.lib.Region} a Region object representing the total area
21710          *                             the element occupies, including any padding
21711          *                             the instance is configured for.
21712          * @static
21713          */
21714         getLocation: function(oDD) {
21715             if (! this.isTypeOfDD(oDD)) {
21716                 return null;
21717             }
21718
21719             var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
21720
21721             try {
21722                 pos= Roo.lib.Dom.getXY(el);
21723             } catch (e) { }
21724
21725             if (!pos) {
21726                 return null;
21727             }
21728
21729             x1 = pos[0];
21730             x2 = x1 + el.offsetWidth;
21731             y1 = pos[1];
21732             y2 = y1 + el.offsetHeight;
21733
21734             t = y1 - oDD.padding[0];
21735             r = x2 + oDD.padding[1];
21736             b = y2 + oDD.padding[2];
21737             l = x1 - oDD.padding[3];
21738
21739             return new Roo.lib.Region( t, r, b, l );
21740         },
21741
21742         /**
21743          * Checks the cursor location to see if it over the target
21744          * @method isOverTarget
21745          * @param {Roo.lib.Point} pt The point to evaluate
21746          * @param {DragDrop} oTarget the DragDrop object we are inspecting
21747          * @return {boolean} true if the mouse is over the target
21748          * @private
21749          * @static
21750          */
21751         isOverTarget: function(pt, oTarget, intersect) {
21752             // use cache if available
21753             var loc = this.locationCache[oTarget.id];
21754             if (!loc || !this.useCache) {
21755                 loc = this.getLocation(oTarget);
21756                 this.locationCache[oTarget.id] = loc;
21757
21758             }
21759
21760             if (!loc) {
21761                 return false;
21762             }
21763
21764             oTarget.cursorIsOver = loc.contains( pt );
21765
21766             // DragDrop is using this as a sanity check for the initial mousedown
21767             // in this case we are done.  In POINT mode, if the drag obj has no
21768             // contraints, we are also done. Otherwise we need to evaluate the
21769             // location of the target as related to the actual location of the
21770             // dragged element.
21771             var dc = this.dragCurrent;
21772             if (!dc || !dc.getTargetCoord ||
21773                     (!intersect && !dc.constrainX && !dc.constrainY)) {
21774                 return oTarget.cursorIsOver;
21775             }
21776
21777             oTarget.overlap = null;
21778
21779             // Get the current location of the drag element, this is the
21780             // location of the mouse event less the delta that represents
21781             // where the original mousedown happened on the element.  We
21782             // need to consider constraints and ticks as well.
21783             var pos = dc.getTargetCoord(pt.x, pt.y);
21784
21785             var el = dc.getDragEl();
21786             var curRegion = new Roo.lib.Region( pos.y,
21787                                                    pos.x + el.offsetWidth,
21788                                                    pos.y + el.offsetHeight,
21789                                                    pos.x );
21790
21791             var overlap = curRegion.intersect(loc);
21792
21793             if (overlap) {
21794                 oTarget.overlap = overlap;
21795                 return (intersect) ? true : oTarget.cursorIsOver;
21796             } else {
21797                 return false;
21798             }
21799         },
21800
21801         /**
21802          * unload event handler
21803          * @method _onUnload
21804          * @private
21805          * @static
21806          */
21807         _onUnload: function(e, me) {
21808             Roo.dd.DragDropMgr.unregAll();
21809         },
21810
21811         /**
21812          * Cleans up the drag and drop events and objects.
21813          * @method unregAll
21814          * @private
21815          * @static
21816          */
21817         unregAll: function() {
21818
21819             if (this.dragCurrent) {
21820                 this.stopDrag();
21821                 this.dragCurrent = null;
21822             }
21823
21824             this._execOnAll("unreg", []);
21825
21826             for (i in this.elementCache) {
21827                 delete this.elementCache[i];
21828             }
21829
21830             this.elementCache = {};
21831             this.ids = {};
21832         },
21833
21834         /**
21835          * A cache of DOM elements
21836          * @property elementCache
21837          * @private
21838          * @static
21839          */
21840         elementCache: {},
21841
21842         /**
21843          * Get the wrapper for the DOM element specified
21844          * @method getElWrapper
21845          * @param {String} id the id of the element to get
21846          * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
21847          * @private
21848          * @deprecated This wrapper isn't that useful
21849          * @static
21850          */
21851         getElWrapper: function(id) {
21852             var oWrapper = this.elementCache[id];
21853             if (!oWrapper || !oWrapper.el) {
21854                 oWrapper = this.elementCache[id] =
21855                     new this.ElementWrapper(Roo.getDom(id));
21856             }
21857             return oWrapper;
21858         },
21859
21860         /**
21861          * Returns the actual DOM element
21862          * @method getElement
21863          * @param {String} id the id of the elment to get
21864          * @return {Object} The element
21865          * @deprecated use Roo.getDom instead
21866          * @static
21867          */
21868         getElement: function(id) {
21869             return Roo.getDom(id);
21870         },
21871
21872         /**
21873          * Returns the style property for the DOM element (i.e.,
21874          * document.getElById(id).style)
21875          * @method getCss
21876          * @param {String} id the id of the elment to get
21877          * @return {Object} The style property of the element
21878          * @deprecated use Roo.getDom instead
21879          * @static
21880          */
21881         getCss: function(id) {
21882             var el = Roo.getDom(id);
21883             return (el) ? el.style : null;
21884         },
21885
21886         /**
21887          * Inner class for cached elements
21888          * @class DragDropMgr.ElementWrapper
21889          * @for DragDropMgr
21890          * @private
21891          * @deprecated
21892          */
21893         ElementWrapper: function(el) {
21894                 /**
21895                  * The element
21896                  * @property el
21897                  */
21898                 this.el = el || null;
21899                 /**
21900                  * The element id
21901                  * @property id
21902                  */
21903                 this.id = this.el && el.id;
21904                 /**
21905                  * A reference to the style property
21906                  * @property css
21907                  */
21908                 this.css = this.el && el.style;
21909             },
21910
21911         /**
21912          * Returns the X position of an html element
21913          * @method getPosX
21914          * @param el the element for which to get the position
21915          * @return {int} the X coordinate
21916          * @for DragDropMgr
21917          * @deprecated use Roo.lib.Dom.getX instead
21918          * @static
21919          */
21920         getPosX: function(el) {
21921             return Roo.lib.Dom.getX(el);
21922         },
21923
21924         /**
21925          * Returns the Y position of an html element
21926          * @method getPosY
21927          * @param el the element for which to get the position
21928          * @return {int} the Y coordinate
21929          * @deprecated use Roo.lib.Dom.getY instead
21930          * @static
21931          */
21932         getPosY: function(el) {
21933             return Roo.lib.Dom.getY(el);
21934         },
21935
21936         /**
21937          * Swap two nodes.  In IE, we use the native method, for others we
21938          * emulate the IE behavior
21939          * @method swapNode
21940          * @param n1 the first node to swap
21941          * @param n2 the other node to swap
21942          * @static
21943          */
21944         swapNode: function(n1, n2) {
21945             if (n1.swapNode) {
21946                 n1.swapNode(n2);
21947             } else {
21948                 var p = n2.parentNode;
21949                 var s = n2.nextSibling;
21950
21951                 if (s == n1) {
21952                     p.insertBefore(n1, n2);
21953                 } else if (n2 == n1.nextSibling) {
21954                     p.insertBefore(n2, n1);
21955                 } else {
21956                     n1.parentNode.replaceChild(n2, n1);
21957                     p.insertBefore(n1, s);
21958                 }
21959             }
21960         },
21961
21962         /**
21963          * Returns the current scroll position
21964          * @method getScroll
21965          * @private
21966          * @static
21967          */
21968         getScroll: function () {
21969             var t, l, dde=document.documentElement, db=document.body;
21970             if (dde && (dde.scrollTop || dde.scrollLeft)) {
21971                 t = dde.scrollTop;
21972                 l = dde.scrollLeft;
21973             } else if (db) {
21974                 t = db.scrollTop;
21975                 l = db.scrollLeft;
21976             } else {
21977
21978             }
21979             return { top: t, left: l };
21980         },
21981
21982         /**
21983          * Returns the specified element style property
21984          * @method getStyle
21985          * @param {HTMLElement} el          the element
21986          * @param {string}      styleProp   the style property
21987          * @return {string} The value of the style property
21988          * @deprecated use Roo.lib.Dom.getStyle
21989          * @static
21990          */
21991         getStyle: function(el, styleProp) {
21992             return Roo.fly(el).getStyle(styleProp);
21993         },
21994
21995         /**
21996          * Gets the scrollTop
21997          * @method getScrollTop
21998          * @return {int} the document's scrollTop
21999          * @static
22000          */
22001         getScrollTop: function () { return this.getScroll().top; },
22002
22003         /**
22004          * Gets the scrollLeft
22005          * @method getScrollLeft
22006          * @return {int} the document's scrollTop
22007          * @static
22008          */
22009         getScrollLeft: function () { return this.getScroll().left; },
22010
22011         /**
22012          * Sets the x/y position of an element to the location of the
22013          * target element.
22014          * @method moveToEl
22015          * @param {HTMLElement} moveEl      The element to move
22016          * @param {HTMLElement} targetEl    The position reference element
22017          * @static
22018          */
22019         moveToEl: function (moveEl, targetEl) {
22020             var aCoord = Roo.lib.Dom.getXY(targetEl);
22021             Roo.lib.Dom.setXY(moveEl, aCoord);
22022         },
22023
22024         /**
22025          * Numeric array sort function
22026          * @method numericSort
22027          * @static
22028          */
22029         numericSort: function(a, b) { return (a - b); },
22030
22031         /**
22032          * Internal counter
22033          * @property _timeoutCount
22034          * @private
22035          * @static
22036          */
22037         _timeoutCount: 0,
22038
22039         /**
22040          * Trying to make the load order less important.  Without this we get
22041          * an error if this file is loaded before the Event Utility.
22042          * @method _addListeners
22043          * @private
22044          * @static
22045          */
22046         _addListeners: function() {
22047             var DDM = Roo.dd.DDM;
22048             if ( Roo.lib.Event && document ) {
22049                 DDM._onLoad();
22050             } else {
22051                 if (DDM._timeoutCount > 2000) {
22052                 } else {
22053                     setTimeout(DDM._addListeners, 10);
22054                     if (document && document.body) {
22055                         DDM._timeoutCount += 1;
22056                     }
22057                 }
22058             }
22059         },
22060
22061         /**
22062          * Recursively searches the immediate parent and all child nodes for
22063          * the handle element in order to determine wheter or not it was
22064          * clicked.
22065          * @method handleWasClicked
22066          * @param node the html element to inspect
22067          * @static
22068          */
22069         handleWasClicked: function(node, id) {
22070             if (this.isHandle(id, node.id)) {
22071                 return true;
22072             } else {
22073                 // check to see if this is a text node child of the one we want
22074                 var p = node.parentNode;
22075
22076                 while (p) {
22077                     if (this.isHandle(id, p.id)) {
22078                         return true;
22079                     } else {
22080                         p = p.parentNode;
22081                     }
22082                 }
22083             }
22084
22085             return false;
22086         }
22087
22088     };
22089
22090 }();
22091
22092 // shorter alias, save a few bytes
22093 Roo.dd.DDM = Roo.dd.DragDropMgr;
22094 Roo.dd.DDM._addListeners();
22095
22096 }/*
22097  * Based on:
22098  * Ext JS Library 1.1.1
22099  * Copyright(c) 2006-2007, Ext JS, LLC.
22100  *
22101  * Originally Released Under LGPL - original licence link has changed is not relivant.
22102  *
22103  * Fork - LGPL
22104  * <script type="text/javascript">
22105  */
22106
22107 /**
22108  * @class Roo.dd.DD
22109  * A DragDrop implementation where the linked element follows the
22110  * mouse cursor during a drag.
22111  * @extends Roo.dd.DragDrop
22112  * @constructor
22113  * @param {String} id the id of the linked element
22114  * @param {String} sGroup the group of related DragDrop items
22115  * @param {object} config an object containing configurable attributes
22116  *                Valid properties for DD:
22117  *                    scroll
22118  */
22119 Roo.dd.DD = function(id, sGroup, config) {
22120     if (id) {
22121         this.init(id, sGroup, config);
22122     }
22123 };
22124
22125 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
22126
22127     /**
22128      * When set to true, the utility automatically tries to scroll the browser
22129      * window wehn a drag and drop element is dragged near the viewport boundary.
22130      * Defaults to true.
22131      * @property scroll
22132      * @type boolean
22133      */
22134     scroll: true,
22135
22136     /**
22137      * Sets the pointer offset to the distance between the linked element's top
22138      * left corner and the location the element was clicked
22139      * @method autoOffset
22140      * @param {int} iPageX the X coordinate of the click
22141      * @param {int} iPageY the Y coordinate of the click
22142      */
22143     autoOffset: function(iPageX, iPageY) {
22144         var x = iPageX - this.startPageX;
22145         var y = iPageY - this.startPageY;
22146         this.setDelta(x, y);
22147     },
22148
22149     /**
22150      * Sets the pointer offset.  You can call this directly to force the
22151      * offset to be in a particular location (e.g., pass in 0,0 to set it
22152      * to the center of the object)
22153      * @method setDelta
22154      * @param {int} iDeltaX the distance from the left
22155      * @param {int} iDeltaY the distance from the top
22156      */
22157     setDelta: function(iDeltaX, iDeltaY) {
22158         this.deltaX = iDeltaX;
22159         this.deltaY = iDeltaY;
22160     },
22161
22162     /**
22163      * Sets the drag element to the location of the mousedown or click event,
22164      * maintaining the cursor location relative to the location on the element
22165      * that was clicked.  Override this if you want to place the element in a
22166      * location other than where the cursor is.
22167      * @method setDragElPos
22168      * @param {int} iPageX the X coordinate of the mousedown or drag event
22169      * @param {int} iPageY the Y coordinate of the mousedown or drag event
22170      */
22171     setDragElPos: function(iPageX, iPageY) {
22172         // the first time we do this, we are going to check to make sure
22173         // the element has css positioning
22174
22175         var el = this.getDragEl();
22176         this.alignElWithMouse(el, iPageX, iPageY);
22177     },
22178
22179     /**
22180      * Sets the element to the location of the mousedown or click event,
22181      * maintaining the cursor location relative to the location on the element
22182      * that was clicked.  Override this if you want to place the element in a
22183      * location other than where the cursor is.
22184      * @method alignElWithMouse
22185      * @param {HTMLElement} el the element to move
22186      * @param {int} iPageX the X coordinate of the mousedown or drag event
22187      * @param {int} iPageY the Y coordinate of the mousedown or drag event
22188      */
22189     alignElWithMouse: function(el, iPageX, iPageY) {
22190         var oCoord = this.getTargetCoord(iPageX, iPageY);
22191         var fly = el.dom ? el : Roo.fly(el);
22192         if (!this.deltaSetXY) {
22193             var aCoord = [oCoord.x, oCoord.y];
22194             fly.setXY(aCoord);
22195             var newLeft = fly.getLeft(true);
22196             var newTop  = fly.getTop(true);
22197             this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
22198         } else {
22199             fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
22200         }
22201
22202         this.cachePosition(oCoord.x, oCoord.y);
22203         this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
22204         return oCoord;
22205     },
22206
22207     /**
22208      * Saves the most recent position so that we can reset the constraints and
22209      * tick marks on-demand.  We need to know this so that we can calculate the
22210      * number of pixels the element is offset from its original position.
22211      * @method cachePosition
22212      * @param iPageX the current x position (optional, this just makes it so we
22213      * don't have to look it up again)
22214      * @param iPageY the current y position (optional, this just makes it so we
22215      * don't have to look it up again)
22216      */
22217     cachePosition: function(iPageX, iPageY) {
22218         if (iPageX) {
22219             this.lastPageX = iPageX;
22220             this.lastPageY = iPageY;
22221         } else {
22222             var aCoord = Roo.lib.Dom.getXY(this.getEl());
22223             this.lastPageX = aCoord[0];
22224             this.lastPageY = aCoord[1];
22225         }
22226     },
22227
22228     /**
22229      * Auto-scroll the window if the dragged object has been moved beyond the
22230      * visible window boundary.
22231      * @method autoScroll
22232      * @param {int} x the drag element's x position
22233      * @param {int} y the drag element's y position
22234      * @param {int} h the height of the drag element
22235      * @param {int} w the width of the drag element
22236      * @private
22237      */
22238     autoScroll: function(x, y, h, w) {
22239
22240         if (this.scroll) {
22241             // The client height
22242             var clientH = Roo.lib.Dom.getViewWidth();
22243
22244             // The client width
22245             var clientW = Roo.lib.Dom.getViewHeight();
22246
22247             // The amt scrolled down
22248             var st = this.DDM.getScrollTop();
22249
22250             // The amt scrolled right
22251             var sl = this.DDM.getScrollLeft();
22252
22253             // Location of the bottom of the element
22254             var bot = h + y;
22255
22256             // Location of the right of the element
22257             var right = w + x;
22258
22259             // The distance from the cursor to the bottom of the visible area,
22260             // adjusted so that we don't scroll if the cursor is beyond the
22261             // element drag constraints
22262             var toBot = (clientH + st - y - this.deltaY);
22263
22264             // The distance from the cursor to the right of the visible area
22265             var toRight = (clientW + sl - x - this.deltaX);
22266
22267
22268             // How close to the edge the cursor must be before we scroll
22269             // var thresh = (document.all) ? 100 : 40;
22270             var thresh = 40;
22271
22272             // How many pixels to scroll per autoscroll op.  This helps to reduce
22273             // clunky scrolling. IE is more sensitive about this ... it needs this
22274             // value to be higher.
22275             var scrAmt = (document.all) ? 80 : 30;
22276
22277             // Scroll down if we are near the bottom of the visible page and the
22278             // obj extends below the crease
22279             if ( bot > clientH && toBot < thresh ) {
22280                 window.scrollTo(sl, st + scrAmt);
22281             }
22282
22283             // Scroll up if the window is scrolled down and the top of the object
22284             // goes above the top border
22285             if ( y < st && st > 0 && y - st < thresh ) {
22286                 window.scrollTo(sl, st - scrAmt);
22287             }
22288
22289             // Scroll right if the obj is beyond the right border and the cursor is
22290             // near the border.
22291             if ( right > clientW && toRight < thresh ) {
22292                 window.scrollTo(sl + scrAmt, st);
22293             }
22294
22295             // Scroll left if the window has been scrolled to the right and the obj
22296             // extends past the left border
22297             if ( x < sl && sl > 0 && x - sl < thresh ) {
22298                 window.scrollTo(sl - scrAmt, st);
22299             }
22300         }
22301     },
22302
22303     /**
22304      * Finds the location the element should be placed if we want to move
22305      * it to where the mouse location less the click offset would place us.
22306      * @method getTargetCoord
22307      * @param {int} iPageX the X coordinate of the click
22308      * @param {int} iPageY the Y coordinate of the click
22309      * @return an object that contains the coordinates (Object.x and Object.y)
22310      * @private
22311      */
22312     getTargetCoord: function(iPageX, iPageY) {
22313
22314
22315         var x = iPageX - this.deltaX;
22316         var y = iPageY - this.deltaY;
22317
22318         if (this.constrainX) {
22319             if (x < this.minX) { x = this.minX; }
22320             if (x > this.maxX) { x = this.maxX; }
22321         }
22322
22323         if (this.constrainY) {
22324             if (y < this.minY) { y = this.minY; }
22325             if (y > this.maxY) { y = this.maxY; }
22326         }
22327
22328         x = this.getTick(x, this.xTicks);
22329         y = this.getTick(y, this.yTicks);
22330
22331
22332         return {x:x, y:y};
22333     },
22334
22335     /*
22336      * Sets up config options specific to this class. Overrides
22337      * Roo.dd.DragDrop, but all versions of this method through the
22338      * inheritance chain are called
22339      */
22340     applyConfig: function() {
22341         Roo.dd.DD.superclass.applyConfig.call(this);
22342         this.scroll = (this.config.scroll !== false);
22343     },
22344
22345     /*
22346      * Event that fires prior to the onMouseDown event.  Overrides
22347      * Roo.dd.DragDrop.
22348      */
22349     b4MouseDown: function(e) {
22350         // this.resetConstraints();
22351         this.autoOffset(e.getPageX(),
22352                             e.getPageY());
22353     },
22354
22355     /*
22356      * Event that fires prior to the onDrag event.  Overrides
22357      * Roo.dd.DragDrop.
22358      */
22359     b4Drag: function(e) {
22360         this.setDragElPos(e.getPageX(),
22361                             e.getPageY());
22362     },
22363
22364     toString: function() {
22365         return ("DD " + this.id);
22366     }
22367
22368     //////////////////////////////////////////////////////////////////////////
22369     // Debugging ygDragDrop events that can be overridden
22370     //////////////////////////////////////////////////////////////////////////
22371     /*
22372     startDrag: function(x, y) {
22373     },
22374
22375     onDrag: function(e) {
22376     },
22377
22378     onDragEnter: function(e, id) {
22379     },
22380
22381     onDragOver: function(e, id) {
22382     },
22383
22384     onDragOut: function(e, id) {
22385     },
22386
22387     onDragDrop: function(e, id) {
22388     },
22389
22390     endDrag: function(e) {
22391     }
22392
22393     */
22394
22395 });/*
22396  * Based on:
22397  * Ext JS Library 1.1.1
22398  * Copyright(c) 2006-2007, Ext JS, LLC.
22399  *
22400  * Originally Released Under LGPL - original licence link has changed is not relivant.
22401  *
22402  * Fork - LGPL
22403  * <script type="text/javascript">
22404  */
22405
22406 /**
22407  * @class Roo.dd.DDProxy
22408  * A DragDrop implementation that inserts an empty, bordered div into
22409  * the document that follows the cursor during drag operations.  At the time of
22410  * the click, the frame div is resized to the dimensions of the linked html
22411  * element, and moved to the exact location of the linked element.
22412  *
22413  * References to the "frame" element refer to the single proxy element that
22414  * was created to be dragged in place of all DDProxy elements on the
22415  * page.
22416  *
22417  * @extends Roo.dd.DD
22418  * @constructor
22419  * @param {String} id the id of the linked html element
22420  * @param {String} sGroup the group of related DragDrop objects
22421  * @param {object} config an object containing configurable attributes
22422  *                Valid properties for DDProxy in addition to those in DragDrop:
22423  *                   resizeFrame, centerFrame, dragElId
22424  */
22425 Roo.dd.DDProxy = function(id, sGroup, config) {
22426     if (id) {
22427         this.init(id, sGroup, config);
22428         this.initFrame();
22429     }
22430 };
22431
22432 /**
22433  * The default drag frame div id
22434  * @property Roo.dd.DDProxy.dragElId
22435  * @type String
22436  * @static
22437  */
22438 Roo.dd.DDProxy.dragElId = "ygddfdiv";
22439
22440 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
22441
22442     /**
22443      * By default we resize the drag frame to be the same size as the element
22444      * we want to drag (this is to get the frame effect).  We can turn it off
22445      * if we want a different behavior.
22446      * @property resizeFrame
22447      * @type boolean
22448      */
22449     resizeFrame: true,
22450
22451     /**
22452      * By default the frame is positioned exactly where the drag element is, so
22453      * we use the cursor offset provided by Roo.dd.DD.  Another option that works only if
22454      * you do not have constraints on the obj is to have the drag frame centered
22455      * around the cursor.  Set centerFrame to true for this effect.
22456      * @property centerFrame
22457      * @type boolean
22458      */
22459     centerFrame: false,
22460
22461     /**
22462      * Creates the proxy element if it does not yet exist
22463      * @method createFrame
22464      */
22465     createFrame: function() {
22466         var self = this;
22467         var body = document.body;
22468
22469         if (!body || !body.firstChild) {
22470             setTimeout( function() { self.createFrame(); }, 50 );
22471             return;
22472         }
22473
22474         var div = this.getDragEl();
22475
22476         if (!div) {
22477             div    = document.createElement("div");
22478             div.id = this.dragElId;
22479             var s  = div.style;
22480
22481             s.position   = "absolute";
22482             s.visibility = "hidden";
22483             s.cursor     = "move";
22484             s.border     = "2px solid #aaa";
22485             s.zIndex     = 999;
22486
22487             // appendChild can blow up IE if invoked prior to the window load event
22488             // while rendering a table.  It is possible there are other scenarios
22489             // that would cause this to happen as well.
22490             body.insertBefore(div, body.firstChild);
22491         }
22492     },
22493
22494     /**
22495      * Initialization for the drag frame element.  Must be called in the
22496      * constructor of all subclasses
22497      * @method initFrame
22498      */
22499     initFrame: function() {
22500         this.createFrame();
22501     },
22502
22503     applyConfig: function() {
22504         Roo.dd.DDProxy.superclass.applyConfig.call(this);
22505
22506         this.resizeFrame = (this.config.resizeFrame !== false);
22507         this.centerFrame = (this.config.centerFrame);
22508         this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
22509     },
22510
22511     /**
22512      * Resizes the drag frame to the dimensions of the clicked object, positions
22513      * it over the object, and finally displays it
22514      * @method showFrame
22515      * @param {int} iPageX X click position
22516      * @param {int} iPageY Y click position
22517      * @private
22518      */
22519     showFrame: function(iPageX, iPageY) {
22520         var el = this.getEl();
22521         var dragEl = this.getDragEl();
22522         var s = dragEl.style;
22523
22524         this._resizeProxy();
22525
22526         if (this.centerFrame) {
22527             this.setDelta( Math.round(parseInt(s.width,  10)/2),
22528                            Math.round(parseInt(s.height, 10)/2) );
22529         }
22530
22531         this.setDragElPos(iPageX, iPageY);
22532
22533         Roo.fly(dragEl).show();
22534     },
22535
22536     /**
22537      * The proxy is automatically resized to the dimensions of the linked
22538      * element when a drag is initiated, unless resizeFrame is set to false
22539      * @method _resizeProxy
22540      * @private
22541      */
22542     _resizeProxy: function() {
22543         if (this.resizeFrame) {
22544             var el = this.getEl();
22545             Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
22546         }
22547     },
22548
22549     // overrides Roo.dd.DragDrop
22550     b4MouseDown: function(e) {
22551         var x = e.getPageX();
22552         var y = e.getPageY();
22553         this.autoOffset(x, y);
22554         this.setDragElPos(x, y);
22555     },
22556
22557     // overrides Roo.dd.DragDrop
22558     b4StartDrag: function(x, y) {
22559         // show the drag frame
22560         this.showFrame(x, y);
22561     },
22562
22563     // overrides Roo.dd.DragDrop
22564     b4EndDrag: function(e) {
22565         Roo.fly(this.getDragEl()).hide();
22566     },
22567
22568     // overrides Roo.dd.DragDrop
22569     // By default we try to move the element to the last location of the frame.
22570     // This is so that the default behavior mirrors that of Roo.dd.DD.
22571     endDrag: function(e) {
22572
22573         var lel = this.getEl();
22574         var del = this.getDragEl();
22575
22576         // Show the drag frame briefly so we can get its position
22577         del.style.visibility = "";
22578
22579         this.beforeMove();
22580         // Hide the linked element before the move to get around a Safari
22581         // rendering bug.
22582         lel.style.visibility = "hidden";
22583         Roo.dd.DDM.moveToEl(lel, del);
22584         del.style.visibility = "hidden";
22585         lel.style.visibility = "";
22586
22587         this.afterDrag();
22588     },
22589
22590     beforeMove : function(){
22591
22592     },
22593
22594     afterDrag : function(){
22595
22596     },
22597
22598     toString: function() {
22599         return ("DDProxy " + this.id);
22600     }
22601
22602 });
22603 /*
22604  * Based on:
22605  * Ext JS Library 1.1.1
22606  * Copyright(c) 2006-2007, Ext JS, LLC.
22607  *
22608  * Originally Released Under LGPL - original licence link has changed is not relivant.
22609  *
22610  * Fork - LGPL
22611  * <script type="text/javascript">
22612  */
22613
22614  /**
22615  * @class Roo.dd.DDTarget
22616  * A DragDrop implementation that does not move, but can be a drop
22617  * target.  You would get the same result by simply omitting implementation
22618  * for the event callbacks, but this way we reduce the processing cost of the
22619  * event listener and the callbacks.
22620  * @extends Roo.dd.DragDrop
22621  * @constructor
22622  * @param {String} id the id of the element that is a drop target
22623  * @param {String} sGroup the group of related DragDrop objects
22624  * @param {object} config an object containing configurable attributes
22625  *                 Valid properties for DDTarget in addition to those in
22626  *                 DragDrop:
22627  *                    none
22628  */
22629 Roo.dd.DDTarget = function(id, sGroup, config) {
22630     if (id) {
22631         this.initTarget(id, sGroup, config);
22632     }
22633     if (config && (config.listeners || config.events)) { 
22634         Roo.dd.DragDrop.superclass.constructor.call(this,  { 
22635             listeners : config.listeners || {}, 
22636             events : config.events || {} 
22637         });    
22638     }
22639 };
22640
22641 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
22642 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
22643     toString: function() {
22644         return ("DDTarget " + this.id);
22645     }
22646 });
22647 /*
22648  * Based on:
22649  * Ext JS Library 1.1.1
22650  * Copyright(c) 2006-2007, Ext JS, LLC.
22651  *
22652  * Originally Released Under LGPL - original licence link has changed is not relivant.
22653  *
22654  * Fork - LGPL
22655  * <script type="text/javascript">
22656  */
22657  
22658
22659 /**
22660  * @class Roo.dd.ScrollManager
22661  * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
22662  * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
22663  * @static
22664  */
22665 Roo.dd.ScrollManager = function(){
22666     var ddm = Roo.dd.DragDropMgr;
22667     var els = {};
22668     var dragEl = null;
22669     var proc = {};
22670     
22671     
22672     
22673     var onStop = function(e){
22674         dragEl = null;
22675         clearProc();
22676     };
22677     
22678     var triggerRefresh = function(){
22679         if(ddm.dragCurrent){
22680              ddm.refreshCache(ddm.dragCurrent.groups);
22681         }
22682     };
22683     
22684     var doScroll = function(){
22685         if(ddm.dragCurrent){
22686             var dds = Roo.dd.ScrollManager;
22687             if(!dds.animate){
22688                 if(proc.el.scroll(proc.dir, dds.increment)){
22689                     triggerRefresh();
22690                 }
22691             }else{
22692                 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
22693             }
22694         }
22695     };
22696     
22697     var clearProc = function(){
22698         if(proc.id){
22699             clearInterval(proc.id);
22700         }
22701         proc.id = 0;
22702         proc.el = null;
22703         proc.dir = "";
22704     };
22705     
22706     var startProc = function(el, dir){
22707          Roo.log('scroll startproc');
22708         clearProc();
22709         proc.el = el;
22710         proc.dir = dir;
22711         proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
22712     };
22713     
22714     var onFire = function(e, isDrop){
22715        
22716         if(isDrop || !ddm.dragCurrent){ return; }
22717         var dds = Roo.dd.ScrollManager;
22718         if(!dragEl || dragEl != ddm.dragCurrent){
22719             dragEl = ddm.dragCurrent;
22720             // refresh regions on drag start
22721             dds.refreshCache();
22722         }
22723         
22724         var xy = Roo.lib.Event.getXY(e);
22725         var pt = new Roo.lib.Point(xy[0], xy[1]);
22726         for(var id in els){
22727             var el = els[id], r = el._region;
22728             if(r && r.contains(pt) && el.isScrollable()){
22729                 if(r.bottom - pt.y <= dds.thresh){
22730                     if(proc.el != el){
22731                         startProc(el, "down");
22732                     }
22733                     return;
22734                 }else if(r.right - pt.x <= dds.thresh){
22735                     if(proc.el != el){
22736                         startProc(el, "left");
22737                     }
22738                     return;
22739                 }else if(pt.y - r.top <= dds.thresh){
22740                     if(proc.el != el){
22741                         startProc(el, "up");
22742                     }
22743                     return;
22744                 }else if(pt.x - r.left <= dds.thresh){
22745                     if(proc.el != el){
22746                         startProc(el, "right");
22747                     }
22748                     return;
22749                 }
22750             }
22751         }
22752         clearProc();
22753     };
22754     
22755     ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
22756     ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
22757     
22758     return {
22759         /**
22760          * Registers new overflow element(s) to auto scroll
22761          * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
22762          */
22763         register : function(el){
22764             if(el instanceof Array){
22765                 for(var i = 0, len = el.length; i < len; i++) {
22766                         this.register(el[i]);
22767                 }
22768             }else{
22769                 el = Roo.get(el);
22770                 els[el.id] = el;
22771             }
22772             Roo.dd.ScrollManager.els = els;
22773         },
22774         
22775         /**
22776          * Unregisters overflow element(s) so they are no longer scrolled
22777          * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
22778          */
22779         unregister : function(el){
22780             if(el instanceof Array){
22781                 for(var i = 0, len = el.length; i < len; i++) {
22782                         this.unregister(el[i]);
22783                 }
22784             }else{
22785                 el = Roo.get(el);
22786                 delete els[el.id];
22787             }
22788         },
22789         
22790         /**
22791          * The number of pixels from the edge of a container the pointer needs to be to 
22792          * trigger scrolling (defaults to 25)
22793          * @type Number
22794          */
22795         thresh : 25,
22796         
22797         /**
22798          * The number of pixels to scroll in each scroll increment (defaults to 50)
22799          * @type Number
22800          */
22801         increment : 100,
22802         
22803         /**
22804          * The frequency of scrolls in milliseconds (defaults to 500)
22805          * @type Number
22806          */
22807         frequency : 500,
22808         
22809         /**
22810          * True to animate the scroll (defaults to true)
22811          * @type Boolean
22812          */
22813         animate: true,
22814         
22815         /**
22816          * The animation duration in seconds - 
22817          * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
22818          * @type Number
22819          */
22820         animDuration: .4,
22821         
22822         /**
22823          * Manually trigger a cache refresh.
22824          */
22825         refreshCache : function(){
22826             for(var id in els){
22827                 if(typeof els[id] == 'object'){ // for people extending the object prototype
22828                     els[id]._region = els[id].getRegion();
22829                 }
22830             }
22831         }
22832     };
22833 }();/*
22834  * Based on:
22835  * Ext JS Library 1.1.1
22836  * Copyright(c) 2006-2007, Ext JS, LLC.
22837  *
22838  * Originally Released Under LGPL - original licence link has changed is not relivant.
22839  *
22840  * Fork - LGPL
22841  * <script type="text/javascript">
22842  */
22843  
22844
22845 /**
22846  * @class Roo.dd.Registry
22847  * Provides easy access to all drag drop components that are registered on a page.  Items can be retrieved either
22848  * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
22849  * @static
22850  */
22851 Roo.dd.Registry = function(){
22852     var elements = {}; 
22853     var handles = {}; 
22854     var autoIdSeed = 0;
22855
22856     var getId = function(el, autogen){
22857         if(typeof el == "string"){
22858             return el;
22859         }
22860         var id = el.id;
22861         if(!id && autogen !== false){
22862             id = "roodd-" + (++autoIdSeed);
22863             el.id = id;
22864         }
22865         return id;
22866     };
22867     
22868     return {
22869     /**
22870      * Register a drag drop element
22871      * @param {String|HTMLElement} element The id or DOM node to register
22872      * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
22873      * in drag drop operations.  You can populate this object with any arbitrary properties that your own code
22874      * knows how to interpret, plus there are some specific properties known to the Registry that should be
22875      * populated in the data object (if applicable):
22876      * <pre>
22877 Value      Description<br />
22878 ---------  ------------------------------------------<br />
22879 handles    Array of DOM nodes that trigger dragging<br />
22880            for the element being registered<br />
22881 isHandle   True if the element passed in triggers<br />
22882            dragging itself, else false
22883 </pre>
22884      */
22885         register : function(el, data){
22886             data = data || {};
22887             if(typeof el == "string"){
22888                 el = document.getElementById(el);
22889             }
22890             data.ddel = el;
22891             elements[getId(el)] = data;
22892             if(data.isHandle !== false){
22893                 handles[data.ddel.id] = data;
22894             }
22895             if(data.handles){
22896                 var hs = data.handles;
22897                 for(var i = 0, len = hs.length; i < len; i++){
22898                         handles[getId(hs[i])] = data;
22899                 }
22900             }
22901         },
22902
22903     /**
22904      * Unregister a drag drop element
22905      * @param {String|HTMLElement}  element The id or DOM node to unregister
22906      */
22907         unregister : function(el){
22908             var id = getId(el, false);
22909             var data = elements[id];
22910             if(data){
22911                 delete elements[id];
22912                 if(data.handles){
22913                     var hs = data.handles;
22914                     for(var i = 0, len = hs.length; i < len; i++){
22915                         delete handles[getId(hs[i], false)];
22916                     }
22917                 }
22918             }
22919         },
22920
22921     /**
22922      * Returns the handle registered for a DOM Node by id
22923      * @param {String|HTMLElement} id The DOM node or id to look up
22924      * @return {Object} handle The custom handle data
22925      */
22926         getHandle : function(id){
22927             if(typeof id != "string"){ // must be element?
22928                 id = id.id;
22929             }
22930             return handles[id];
22931         },
22932
22933     /**
22934      * Returns the handle that is registered for the DOM node that is the target of the event
22935      * @param {Event} e The event
22936      * @return {Object} handle The custom handle data
22937      */
22938         getHandleFromEvent : function(e){
22939             var t = Roo.lib.Event.getTarget(e);
22940             return t ? handles[t.id] : null;
22941         },
22942
22943     /**
22944      * Returns a custom data object that is registered for a DOM node by id
22945      * @param {String|HTMLElement} id The DOM node or id to look up
22946      * @return {Object} data The custom data
22947      */
22948         getTarget : function(id){
22949             if(typeof id != "string"){ // must be element?
22950                 id = id.id;
22951             }
22952             return elements[id];
22953         },
22954
22955     /**
22956      * Returns a custom data object that is registered for the DOM node that is the target of the event
22957      * @param {Event} e The event
22958      * @return {Object} data The custom data
22959      */
22960         getTargetFromEvent : function(e){
22961             var t = Roo.lib.Event.getTarget(e);
22962             return t ? elements[t.id] || handles[t.id] : null;
22963         }
22964     };
22965 }();/*
22966  * Based on:
22967  * Ext JS Library 1.1.1
22968  * Copyright(c) 2006-2007, Ext JS, LLC.
22969  *
22970  * Originally Released Under LGPL - original licence link has changed is not relivant.
22971  *
22972  * Fork - LGPL
22973  * <script type="text/javascript">
22974  */
22975  
22976
22977 /**
22978  * @class Roo.dd.StatusProxy
22979  * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair.  This is the
22980  * default drag proxy used by all Roo.dd components.
22981  * @constructor
22982  * @param {Object} config
22983  */
22984 Roo.dd.StatusProxy = function(config){
22985     Roo.apply(this, config);
22986     this.id = this.id || Roo.id();
22987     this.el = new Roo.Layer({
22988         dh: {
22989             id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
22990                 {tag: "div", cls: "x-dd-drop-icon"},
22991                 {tag: "div", cls: "x-dd-drag-ghost"}
22992             ]
22993         }, 
22994         shadow: !config || config.shadow !== false
22995     });
22996     this.ghost = Roo.get(this.el.dom.childNodes[1]);
22997     this.dropStatus = this.dropNotAllowed;
22998 };
22999
23000 Roo.dd.StatusProxy.prototype = {
23001     /**
23002      * @cfg {String} dropAllowed
23003      * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
23004      */
23005     dropAllowed : "x-dd-drop-ok",
23006     /**
23007      * @cfg {String} dropNotAllowed
23008      * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
23009      */
23010     dropNotAllowed : "x-dd-drop-nodrop",
23011
23012     /**
23013      * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
23014      * over the current target element.
23015      * @param {String} cssClass The css class for the new drop status indicator image
23016      */
23017     setStatus : function(cssClass){
23018         cssClass = cssClass || this.dropNotAllowed;
23019         if(this.dropStatus != cssClass){
23020             this.el.replaceClass(this.dropStatus, cssClass);
23021             this.dropStatus = cssClass;
23022         }
23023     },
23024
23025     /**
23026      * Resets the status indicator to the default dropNotAllowed value
23027      * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
23028      */
23029     reset : function(clearGhost){
23030         this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
23031         this.dropStatus = this.dropNotAllowed;
23032         if(clearGhost){
23033             this.ghost.update("");
23034         }
23035     },
23036
23037     /**
23038      * Updates the contents of the ghost element
23039      * @param {String} html The html that will replace the current innerHTML of the ghost element
23040      */
23041     update : function(html){
23042         if(typeof html == "string"){
23043             this.ghost.update(html);
23044         }else{
23045             this.ghost.update("");
23046             html.style.margin = "0";
23047             this.ghost.dom.appendChild(html);
23048         }
23049         // ensure float = none set?? cant remember why though.
23050         var el = this.ghost.dom.firstChild;
23051                 if(el){
23052                         Roo.fly(el).setStyle('float', 'none');
23053                 }
23054     },
23055     
23056     /**
23057      * Returns the underlying proxy {@link Roo.Layer}
23058      * @return {Roo.Layer} el
23059     */
23060     getEl : function(){
23061         return this.el;
23062     },
23063
23064     /**
23065      * Returns the ghost element
23066      * @return {Roo.Element} el
23067      */
23068     getGhost : function(){
23069         return this.ghost;
23070     },
23071
23072     /**
23073      * Hides the proxy
23074      * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
23075      */
23076     hide : function(clear){
23077         this.el.hide();
23078         if(clear){
23079             this.reset(true);
23080         }
23081     },
23082
23083     /**
23084      * Stops the repair animation if it's currently running
23085      */
23086     stop : function(){
23087         if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
23088             this.anim.stop();
23089         }
23090     },
23091
23092     /**
23093      * Displays this proxy
23094      */
23095     show : function(){
23096         this.el.show();
23097     },
23098
23099     /**
23100      * Force the Layer to sync its shadow and shim positions to the element
23101      */
23102     sync : function(){
23103         this.el.sync();
23104     },
23105
23106     /**
23107      * Causes the proxy to return to its position of origin via an animation.  Should be called after an
23108      * invalid drop operation by the item being dragged.
23109      * @param {Array} xy The XY position of the element ([x, y])
23110      * @param {Function} callback The function to call after the repair is complete
23111      * @param {Object} scope The scope in which to execute the callback
23112      */
23113     repair : function(xy, callback, scope){
23114         this.callback = callback;
23115         this.scope = scope;
23116         if(xy && this.animRepair !== false){
23117             this.el.addClass("x-dd-drag-repair");
23118             this.el.hideUnders(true);
23119             this.anim = this.el.shift({
23120                 duration: this.repairDuration || .5,
23121                 easing: 'easeOut',
23122                 xy: xy,
23123                 stopFx: true,
23124                 callback: this.afterRepair,
23125                 scope: this
23126             });
23127         }else{
23128             this.afterRepair();
23129         }
23130     },
23131
23132     // private
23133     afterRepair : function(){
23134         this.hide(true);
23135         if(typeof this.callback == "function"){
23136             this.callback.call(this.scope || this);
23137         }
23138         this.callback = null;
23139         this.scope = null;
23140     }
23141 };/*
23142  * Based on:
23143  * Ext JS Library 1.1.1
23144  * Copyright(c) 2006-2007, Ext JS, LLC.
23145  *
23146  * Originally Released Under LGPL - original licence link has changed is not relivant.
23147  *
23148  * Fork - LGPL
23149  * <script type="text/javascript">
23150  */
23151
23152 /**
23153  * @class Roo.dd.DragSource
23154  * @extends Roo.dd.DDProxy
23155  * A simple class that provides the basic implementation needed to make any element draggable.
23156  * @constructor
23157  * @param {String/HTMLElement/Element} el The container element
23158  * @param {Object} config
23159  */
23160 Roo.dd.DragSource = function(el, config){
23161     this.el = Roo.get(el);
23162     this.dragData = {};
23163     
23164     Roo.apply(this, config);
23165     
23166     if(!this.proxy){
23167         this.proxy = new Roo.dd.StatusProxy();
23168     }
23169
23170     Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
23171           {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
23172     
23173     this.dragging = false;
23174 };
23175
23176 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
23177     /**
23178      * @cfg {String} dropAllowed
23179      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
23180      */
23181     dropAllowed : "x-dd-drop-ok",
23182     /**
23183      * @cfg {String} dropNotAllowed
23184      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
23185      */
23186     dropNotAllowed : "x-dd-drop-nodrop",
23187
23188     /**
23189      * Returns the data object associated with this drag source
23190      * @return {Object} data An object containing arbitrary data
23191      */
23192     getDragData : function(e){
23193         return this.dragData;
23194     },
23195
23196     // private
23197     onDragEnter : function(e, id){
23198         var target = Roo.dd.DragDropMgr.getDDById(id);
23199         this.cachedTarget = target;
23200         if(this.beforeDragEnter(target, e, id) !== false){
23201             if(target.isNotifyTarget){
23202                 var status = target.notifyEnter(this, e, this.dragData);
23203                 this.proxy.setStatus(status);
23204             }else{
23205                 this.proxy.setStatus(this.dropAllowed);
23206             }
23207             
23208             if(this.afterDragEnter){
23209                 /**
23210                  * An empty function by default, but provided so that you can perform a custom action
23211                  * when the dragged item enters the drop target by providing an implementation.
23212                  * @param {Roo.dd.DragDrop} target The drop target
23213                  * @param {Event} e The event object
23214                  * @param {String} id The id of the dragged element
23215                  * @method afterDragEnter
23216                  */
23217                 this.afterDragEnter(target, e, id);
23218             }
23219         }
23220     },
23221
23222     /**
23223      * An empty function by default, but provided so that you can perform a custom action
23224      * before the dragged item enters the drop target and optionally cancel the onDragEnter.
23225      * @param {Roo.dd.DragDrop} target The drop target
23226      * @param {Event} e The event object
23227      * @param {String} id The id of the dragged element
23228      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23229      */
23230     beforeDragEnter : function(target, e, id){
23231         return true;
23232     },
23233
23234     // private
23235     alignElWithMouse: function() {
23236         Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
23237         this.proxy.sync();
23238     },
23239
23240     // private
23241     onDragOver : function(e, id){
23242         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23243         if(this.beforeDragOver(target, e, id) !== false){
23244             if(target.isNotifyTarget){
23245                 var status = target.notifyOver(this, e, this.dragData);
23246                 this.proxy.setStatus(status);
23247             }
23248
23249             if(this.afterDragOver){
23250                 /**
23251                  * An empty function by default, but provided so that you can perform a custom action
23252                  * while the dragged item is over the drop target by providing an implementation.
23253                  * @param {Roo.dd.DragDrop} target The drop target
23254                  * @param {Event} e The event object
23255                  * @param {String} id The id of the dragged element
23256                  * @method afterDragOver
23257                  */
23258                 this.afterDragOver(target, e, id);
23259             }
23260         }
23261     },
23262
23263     /**
23264      * An empty function by default, but provided so that you can perform a custom action
23265      * while the dragged item is over the drop target and optionally cancel the onDragOver.
23266      * @param {Roo.dd.DragDrop} target The drop target
23267      * @param {Event} e The event object
23268      * @param {String} id The id of the dragged element
23269      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23270      */
23271     beforeDragOver : function(target, e, id){
23272         return true;
23273     },
23274
23275     // private
23276     onDragOut : function(e, id){
23277         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23278         if(this.beforeDragOut(target, e, id) !== false){
23279             if(target.isNotifyTarget){
23280                 target.notifyOut(this, e, this.dragData);
23281             }
23282             this.proxy.reset();
23283             if(this.afterDragOut){
23284                 /**
23285                  * An empty function by default, but provided so that you can perform a custom action
23286                  * after the dragged item is dragged out of the target without dropping.
23287                  * @param {Roo.dd.DragDrop} target The drop target
23288                  * @param {Event} e The event object
23289                  * @param {String} id The id of the dragged element
23290                  * @method afterDragOut
23291                  */
23292                 this.afterDragOut(target, e, id);
23293             }
23294         }
23295         this.cachedTarget = null;
23296     },
23297
23298     /**
23299      * An empty function by default, but provided so that you can perform a custom action before the dragged
23300      * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
23301      * @param {Roo.dd.DragDrop} target The drop target
23302      * @param {Event} e The event object
23303      * @param {String} id The id of the dragged element
23304      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23305      */
23306     beforeDragOut : function(target, e, id){
23307         return true;
23308     },
23309     
23310     // private
23311     onDragDrop : function(e, id){
23312         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23313         if(this.beforeDragDrop(target, e, id) !== false){
23314             if(target.isNotifyTarget){
23315                 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
23316                     this.onValidDrop(target, e, id);
23317                 }else{
23318                     this.onInvalidDrop(target, e, id);
23319                 }
23320             }else{
23321                 this.onValidDrop(target, e, id);
23322             }
23323             
23324             if(this.afterDragDrop){
23325                 /**
23326                  * An empty function by default, but provided so that you can perform a custom action
23327                  * after a valid drag drop has occurred by providing an implementation.
23328                  * @param {Roo.dd.DragDrop} target The drop target
23329                  * @param {Event} e The event object
23330                  * @param {String} id The id of the dropped element
23331                  * @method afterDragDrop
23332                  */
23333                 this.afterDragDrop(target, e, id);
23334             }
23335         }
23336         delete this.cachedTarget;
23337     },
23338
23339     /**
23340      * An empty function by default, but provided so that you can perform a custom action before the dragged
23341      * item is dropped onto the target and optionally cancel the onDragDrop.
23342      * @param {Roo.dd.DragDrop} target The drop target
23343      * @param {Event} e The event object
23344      * @param {String} id The id of the dragged element
23345      * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
23346      */
23347     beforeDragDrop : function(target, e, id){
23348         return true;
23349     },
23350
23351     // private
23352     onValidDrop : function(target, e, id){
23353         this.hideProxy();
23354         if(this.afterValidDrop){
23355             /**
23356              * An empty function by default, but provided so that you can perform a custom action
23357              * after a valid drop has occurred by providing an implementation.
23358              * @param {Object} target The target DD 
23359              * @param {Event} e The event object
23360              * @param {String} id The id of the dropped element
23361              * @method afterInvalidDrop
23362              */
23363             this.afterValidDrop(target, e, id);
23364         }
23365     },
23366
23367     // private
23368     getRepairXY : function(e, data){
23369         return this.el.getXY();  
23370     },
23371
23372     // private
23373     onInvalidDrop : function(target, e, id){
23374         this.beforeInvalidDrop(target, e, id);
23375         if(this.cachedTarget){
23376             if(this.cachedTarget.isNotifyTarget){
23377                 this.cachedTarget.notifyOut(this, e, this.dragData);
23378             }
23379             this.cacheTarget = null;
23380         }
23381         this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
23382
23383         if(this.afterInvalidDrop){
23384             /**
23385              * An empty function by default, but provided so that you can perform a custom action
23386              * after an invalid drop has occurred by providing an implementation.
23387              * @param {Event} e The event object
23388              * @param {String} id The id of the dropped element
23389              * @method afterInvalidDrop
23390              */
23391             this.afterInvalidDrop(e, id);
23392         }
23393     },
23394
23395     // private
23396     afterRepair : function(){
23397         if(Roo.enableFx){
23398             this.el.highlight(this.hlColor || "c3daf9");
23399         }
23400         this.dragging = false;
23401     },
23402
23403     /**
23404      * An empty function by default, but provided so that you can perform a custom action after an invalid
23405      * drop has occurred.
23406      * @param {Roo.dd.DragDrop} target The drop target
23407      * @param {Event} e The event object
23408      * @param {String} id The id of the dragged element
23409      * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
23410      */
23411     beforeInvalidDrop : function(target, e, id){
23412         return true;
23413     },
23414
23415     // private
23416     handleMouseDown : function(e){
23417         if(this.dragging) {
23418             return;
23419         }
23420         var data = this.getDragData(e);
23421         if(data && this.onBeforeDrag(data, e) !== false){
23422             this.dragData = data;
23423             this.proxy.stop();
23424             Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
23425         } 
23426     },
23427
23428     /**
23429      * An empty function by default, but provided so that you can perform a custom action before the initial
23430      * drag event begins and optionally cancel it.
23431      * @param {Object} data An object containing arbitrary data to be shared with drop targets
23432      * @param {Event} e The event object
23433      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23434      */
23435     onBeforeDrag : function(data, e){
23436         return true;
23437     },
23438
23439     /**
23440      * An empty function by default, but provided so that you can perform a custom action once the initial
23441      * drag event has begun.  The drag cannot be canceled from this function.
23442      * @param {Number} x The x position of the click on the dragged object
23443      * @param {Number} y The y position of the click on the dragged object
23444      */
23445     onStartDrag : Roo.emptyFn,
23446
23447     // private - YUI override
23448     startDrag : function(x, y){
23449         this.proxy.reset();
23450         this.dragging = true;
23451         this.proxy.update("");
23452         this.onInitDrag(x, y);
23453         this.proxy.show();
23454     },
23455
23456     // private
23457     onInitDrag : function(x, y){
23458         var clone = this.el.dom.cloneNode(true);
23459         clone.id = Roo.id(); // prevent duplicate ids
23460         this.proxy.update(clone);
23461         this.onStartDrag(x, y);
23462         return true;
23463     },
23464
23465     /**
23466      * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
23467      * @return {Roo.dd.StatusProxy} proxy The StatusProxy
23468      */
23469     getProxy : function(){
23470         return this.proxy;  
23471     },
23472
23473     /**
23474      * Hides the drag source's {@link Roo.dd.StatusProxy}
23475      */
23476     hideProxy : function(){
23477         this.proxy.hide();  
23478         this.proxy.reset(true);
23479         this.dragging = false;
23480     },
23481
23482     // private
23483     triggerCacheRefresh : function(){
23484         Roo.dd.DDM.refreshCache(this.groups);
23485     },
23486
23487     // private - override to prevent hiding
23488     b4EndDrag: function(e) {
23489     },
23490
23491     // private - override to prevent moving
23492     endDrag : function(e){
23493         this.onEndDrag(this.dragData, e);
23494     },
23495
23496     // private
23497     onEndDrag : function(data, e){
23498     },
23499     
23500     // private - pin to cursor
23501     autoOffset : function(x, y) {
23502         this.setDelta(-12, -20);
23503     }    
23504 });/*
23505  * Based on:
23506  * Ext JS Library 1.1.1
23507  * Copyright(c) 2006-2007, Ext JS, LLC.
23508  *
23509  * Originally Released Under LGPL - original licence link has changed is not relivant.
23510  *
23511  * Fork - LGPL
23512  * <script type="text/javascript">
23513  */
23514
23515
23516 /**
23517  * @class Roo.dd.DropTarget
23518  * @extends Roo.dd.DDTarget
23519  * A simple class that provides the basic implementation needed to make any element a drop target that can have
23520  * draggable items dropped onto it.  The drop has no effect until an implementation of notifyDrop is provided.
23521  * @constructor
23522  * @param {String/HTMLElement/Element} el The container element
23523  * @param {Object} config
23524  */
23525 Roo.dd.DropTarget = function(el, config){
23526     this.el = Roo.get(el);
23527     
23528     var listeners = false; ;
23529     if (config && config.listeners) {
23530         listeners= config.listeners;
23531         delete config.listeners;
23532     }
23533     Roo.apply(this, config);
23534     
23535     if(this.containerScroll){
23536         Roo.dd.ScrollManager.register(this.el);
23537     }
23538     this.addEvents( {
23539          /**
23540          * @scope Roo.dd.DropTarget
23541          */
23542          
23543          /**
23544          * @event enter
23545          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
23546          * target.  This default implementation adds the CSS class specified by overClass (if any) to the drop element
23547          * and returns the dropAllowed config value.  This method should be overridden if drop validation is required.
23548          * 
23549          * IMPORTANT : it should set  this.valid to true|false
23550          * 
23551          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23552          * @param {Event} e The event
23553          * @param {Object} data An object containing arbitrary data supplied by the drag source
23554          */
23555         "enter" : true,
23556         
23557          /**
23558          * @event over
23559          * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
23560          * This method will be called on every mouse movement while the drag source is over the drop target.
23561          * This default implementation simply returns the dropAllowed config value.
23562          * 
23563          * IMPORTANT : it should set  this.valid to true|false
23564          * 
23565          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23566          * @param {Event} e The event
23567          * @param {Object} data An object containing arbitrary data supplied by the drag source
23568          
23569          */
23570         "over" : true,
23571         /**
23572          * @event out
23573          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
23574          * out of the target without dropping.  This default implementation simply removes the CSS class specified by
23575          * overClass (if any) from the drop element.
23576          * 
23577          * 
23578          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23579          * @param {Event} e The event
23580          * @param {Object} data An object containing arbitrary data supplied by the drag source
23581          */
23582          "out" : true,
23583          
23584         /**
23585          * @event drop
23586          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
23587          * been dropped on it.  This method has no default implementation and returns false, so you must provide an
23588          * implementation that does something to process the drop event and returns true so that the drag source's
23589          * repair action does not run.
23590          * 
23591          * IMPORTANT : it should set this.success
23592          * 
23593          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23594          * @param {Event} e The event
23595          * @param {Object} data An object containing arbitrary data supplied by the drag source
23596         */
23597          "drop" : true
23598     });
23599             
23600      
23601     Roo.dd.DropTarget.superclass.constructor.call(  this, 
23602         this.el.dom, 
23603         this.ddGroup || this.group,
23604         {
23605             isTarget: true,
23606             listeners : listeners || {} 
23607            
23608         
23609         }
23610     );
23611
23612 };
23613
23614 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
23615     /**
23616      * @cfg {String} overClass
23617      * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
23618      */
23619      /**
23620      * @cfg {String} ddGroup
23621      * The drag drop group to handle drop events for
23622      */
23623      
23624     /**
23625      * @cfg {String} dropAllowed
23626      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
23627      */
23628     dropAllowed : "x-dd-drop-ok",
23629     /**
23630      * @cfg {String} dropNotAllowed
23631      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
23632      */
23633     dropNotAllowed : "x-dd-drop-nodrop",
23634     /**
23635      * @cfg {boolean} success
23636      * set this after drop listener.. 
23637      */
23638     success : false,
23639     /**
23640      * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
23641      * if the drop point is valid for over/enter..
23642      */
23643     valid : false,
23644     // private
23645     isTarget : true,
23646
23647     // private
23648     isNotifyTarget : true,
23649     
23650     /**
23651      * @hide
23652      */
23653     notifyEnter : function(dd, e, data)
23654     {
23655         this.valid = true;
23656         this.fireEvent('enter', dd, e, data);
23657         if(this.overClass){
23658             this.el.addClass(this.overClass);
23659         }
23660         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
23661             this.valid ? this.dropAllowed : this.dropNotAllowed
23662         );
23663     },
23664
23665     /**
23666      * @hide
23667      */
23668     notifyOver : function(dd, e, data)
23669     {
23670         this.valid = true;
23671         this.fireEvent('over', dd, e, data);
23672         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
23673             this.valid ? this.dropAllowed : this.dropNotAllowed
23674         );
23675     },
23676
23677     /**
23678      * @hide
23679      */
23680     notifyOut : function(dd, e, data)
23681     {
23682         this.fireEvent('out', dd, e, data);
23683         if(this.overClass){
23684             this.el.removeClass(this.overClass);
23685         }
23686     },
23687
23688     /**
23689      * @hide
23690      */
23691     notifyDrop : function(dd, e, data)
23692     {
23693         this.success = false;
23694         this.fireEvent('drop', dd, e, data);
23695         return this.success;
23696     }
23697 });/*
23698  * Based on:
23699  * Ext JS Library 1.1.1
23700  * Copyright(c) 2006-2007, Ext JS, LLC.
23701  *
23702  * Originally Released Under LGPL - original licence link has changed is not relivant.
23703  *
23704  * Fork - LGPL
23705  * <script type="text/javascript">
23706  */
23707
23708
23709 /**
23710  * @class Roo.dd.DragZone
23711  * @extends Roo.dd.DragSource
23712  * This class provides a container DD instance that proxies for multiple child node sources.<br />
23713  * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
23714  * @constructor
23715  * @param {String/HTMLElement/Element} el The container element
23716  * @param {Object} config
23717  */
23718 Roo.dd.DragZone = function(el, config){
23719     Roo.dd.DragZone.superclass.constructor.call(this, el, config);
23720     if(this.containerScroll){
23721         Roo.dd.ScrollManager.register(this.el);
23722     }
23723 };
23724
23725 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
23726     /**
23727      * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
23728      * for auto scrolling during drag operations.
23729      */
23730     /**
23731      * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
23732      * method after a failed drop (defaults to "c3daf9" - light blue)
23733      */
23734
23735     /**
23736      * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
23737      * for a valid target to drag based on the mouse down. Override this method
23738      * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
23739      * object has a "ddel" attribute (with an HTML Element) for other functions to work.
23740      * @param {EventObject} e The mouse down event
23741      * @return {Object} The dragData
23742      */
23743     getDragData : function(e){
23744         return Roo.dd.Registry.getHandleFromEvent(e);
23745     },
23746     
23747     /**
23748      * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
23749      * this.dragData.ddel
23750      * @param {Number} x The x position of the click on the dragged object
23751      * @param {Number} y The y position of the click on the dragged object
23752      * @return {Boolean} true to continue the drag, false to cancel
23753      */
23754     onInitDrag : function(x, y){
23755         this.proxy.update(this.dragData.ddel.cloneNode(true));
23756         this.onStartDrag(x, y);
23757         return true;
23758     },
23759     
23760     /**
23761      * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel 
23762      */
23763     afterRepair : function(){
23764         if(Roo.enableFx){
23765             Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
23766         }
23767         this.dragging = false;
23768     },
23769
23770     /**
23771      * Called before a repair of an invalid drop to get the XY to animate to. By default returns
23772      * the XY of this.dragData.ddel
23773      * @param {EventObject} e The mouse up event
23774      * @return {Array} The xy location (e.g. [100, 200])
23775      */
23776     getRepairXY : function(e){
23777         return Roo.Element.fly(this.dragData.ddel).getXY();  
23778     }
23779 });/*
23780  * Based on:
23781  * Ext JS Library 1.1.1
23782  * Copyright(c) 2006-2007, Ext JS, LLC.
23783  *
23784  * Originally Released Under LGPL - original licence link has changed is not relivant.
23785  *
23786  * Fork - LGPL
23787  * <script type="text/javascript">
23788  */
23789 /**
23790  * @class Roo.dd.DropZone
23791  * @extends Roo.dd.DropTarget
23792  * This class provides a container DD instance that proxies for multiple child node targets.<br />
23793  * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
23794  * @constructor
23795  * @param {String/HTMLElement/Element} el The container element
23796  * @param {Object} config
23797  */
23798 Roo.dd.DropZone = function(el, config){
23799     Roo.dd.DropZone.superclass.constructor.call(this, el, config);
23800 };
23801
23802 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
23803     /**
23804      * Returns a custom data object associated with the DOM node that is the target of the event.  By default
23805      * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
23806      * provide your own custom lookup.
23807      * @param {Event} e The event
23808      * @return {Object} data The custom data
23809      */
23810     getTargetFromEvent : function(e){
23811         return Roo.dd.Registry.getTargetFromEvent(e);
23812     },
23813
23814     /**
23815      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
23816      * that it has registered.  This method has no default implementation and should be overridden to provide
23817      * node-specific processing if necessary.
23818      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from 
23819      * {@link #getTargetFromEvent} for this node)
23820      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23821      * @param {Event} e The event
23822      * @param {Object} data An object containing arbitrary data supplied by the drag source
23823      */
23824     onNodeEnter : function(n, dd, e, data){
23825         
23826     },
23827
23828     /**
23829      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
23830      * that it has registered.  The default implementation returns this.dropNotAllowed, so it should be
23831      * overridden to provide the proper feedback.
23832      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
23833      * {@link #getTargetFromEvent} for this node)
23834      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23835      * @param {Event} e The event
23836      * @param {Object} data An object containing arbitrary data supplied by the drag source
23837      * @return {String} status The CSS class that communicates the drop status back to the source so that the
23838      * underlying {@link Roo.dd.StatusProxy} can be updated
23839      */
23840     onNodeOver : function(n, dd, e, data){
23841         return this.dropAllowed;
23842     },
23843
23844     /**
23845      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
23846      * the drop node without dropping.  This method has no default implementation and should be overridden to provide
23847      * node-specific processing if necessary.
23848      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
23849      * {@link #getTargetFromEvent} for this node)
23850      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23851      * @param {Event} e The event
23852      * @param {Object} data An object containing arbitrary data supplied by the drag source
23853      */
23854     onNodeOut : function(n, dd, e, data){
23855         
23856     },
23857
23858     /**
23859      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
23860      * the drop node.  The default implementation returns false, so it should be overridden to provide the
23861      * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
23862      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
23863      * {@link #getTargetFromEvent} for this node)
23864      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23865      * @param {Event} e The event
23866      * @param {Object} data An object containing arbitrary data supplied by the drag source
23867      * @return {Boolean} True if the drop was valid, else false
23868      */
23869     onNodeDrop : function(n, dd, e, data){
23870         return false;
23871     },
23872
23873     /**
23874      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
23875      * but not over any of its registered drop nodes.  The default implementation returns this.dropNotAllowed, so
23876      * it should be overridden to provide the proper feedback if necessary.
23877      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23878      * @param {Event} e The event
23879      * @param {Object} data An object containing arbitrary data supplied by the drag source
23880      * @return {String} status The CSS class that communicates the drop status back to the source so that the
23881      * underlying {@link Roo.dd.StatusProxy} can be updated
23882      */
23883     onContainerOver : function(dd, e, data){
23884         return this.dropNotAllowed;
23885     },
23886
23887     /**
23888      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
23889      * but not on any of its registered drop nodes.  The default implementation returns false, so it should be
23890      * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
23891      * be able to accept drops.  It should return true when valid so that the drag source's repair action does not run.
23892      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23893      * @param {Event} e The event
23894      * @param {Object} data An object containing arbitrary data supplied by the drag source
23895      * @return {Boolean} True if the drop was valid, else false
23896      */
23897     onContainerDrop : function(dd, e, data){
23898         return false;
23899     },
23900
23901     /**
23902      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
23903      * the zone.  The default implementation returns this.dropNotAllowed and expects that only registered drop
23904      * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
23905      * you should override this method and provide a custom implementation.
23906      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23907      * @param {Event} e The event
23908      * @param {Object} data An object containing arbitrary data supplied by the drag source
23909      * @return {String} status The CSS class that communicates the drop status back to the source so that the
23910      * underlying {@link Roo.dd.StatusProxy} can be updated
23911      */
23912     notifyEnter : function(dd, e, data){
23913         return this.dropNotAllowed;
23914     },
23915
23916     /**
23917      * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
23918      * This method will be called on every mouse movement while the drag source is over the drop zone.
23919      * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
23920      * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
23921      * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
23922      * registered node, it will call {@link #onContainerOver}.
23923      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23924      * @param {Event} e The event
23925      * @param {Object} data An object containing arbitrary data supplied by the drag source
23926      * @return {String} status The CSS class that communicates the drop status back to the source so that the
23927      * underlying {@link Roo.dd.StatusProxy} can be updated
23928      */
23929     notifyOver : function(dd, e, data){
23930         var n = this.getTargetFromEvent(e);
23931         if(!n){ // not over valid drop target
23932             if(this.lastOverNode){
23933                 this.onNodeOut(this.lastOverNode, dd, e, data);
23934                 this.lastOverNode = null;
23935             }
23936             return this.onContainerOver(dd, e, data);
23937         }
23938         if(this.lastOverNode != n){
23939             if(this.lastOverNode){
23940                 this.onNodeOut(this.lastOverNode, dd, e, data);
23941             }
23942             this.onNodeEnter(n, dd, e, data);
23943             this.lastOverNode = n;
23944         }
23945         return this.onNodeOver(n, dd, e, data);
23946     },
23947
23948     /**
23949      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
23950      * out of the zone without dropping.  If the drag source is currently over a registered node, the notification
23951      * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
23952      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23953      * @param {Event} e The event
23954      * @param {Object} data An object containing arbitrary data supplied by the drag zone
23955      */
23956     notifyOut : function(dd, e, data){
23957         if(this.lastOverNode){
23958             this.onNodeOut(this.lastOverNode, dd, e, data);
23959             this.lastOverNode = null;
23960         }
23961     },
23962
23963     /**
23964      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
23965      * been dropped on it.  The drag zone will look up the target node based on the event passed in, and if there
23966      * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
23967      * otherwise it will call {@link #onContainerDrop}.
23968      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23969      * @param {Event} e The event
23970      * @param {Object} data An object containing arbitrary data supplied by the drag source
23971      * @return {Boolean} True if the drop was valid, else false
23972      */
23973     notifyDrop : function(dd, e, data){
23974         if(this.lastOverNode){
23975             this.onNodeOut(this.lastOverNode, dd, e, data);
23976             this.lastOverNode = null;
23977         }
23978         var n = this.getTargetFromEvent(e);
23979         return n ?
23980             this.onNodeDrop(n, dd, e, data) :
23981             this.onContainerDrop(dd, e, data);
23982     },
23983
23984     // private
23985     triggerCacheRefresh : function(){
23986         Roo.dd.DDM.refreshCache(this.groups);
23987     }  
23988 });