roojs-core.js
[roojs1] / roojs-core-debug.js
1 /*
2  * Based on:
3  * Ext JS Library 1.1.1
4  * Copyright(c) 2006-2007, Ext JS, LLC.
5  *
6  * Originally Released Under LGPL - original licence link has changed is not relivant.
7  *
8  * Fork - LGPL
9  * <script type="text/javascript">
10  */
11  
12
13
14
15
16 // for old browsers
17 window["undefined"] = window["undefined"];
18
19 /**
20  * @class Roo
21  * Roo core utilities and functions.
22  * @static
23  */
24 var Roo = {}; 
25 /**
26  * Copies all the properties of config to obj.
27  * @param {Object} obj The receiver of the properties
28  * @param {Object} config The source of the properties
29  * @param {Object} defaults A different object that will also be applied for default values
30  * @return {Object} returns obj
31  * @member Roo apply
32  */
33
34  
35 Roo.apply = function(o, c, defaults){
36     if(defaults){
37         // no "this" reference for friendly out of scope calls
38         Roo.apply(o, defaults);
39     }
40     if(o && c && typeof c == 'object'){
41         for(var p in c){
42             o[p] = c[p];
43         }
44     }
45     return o;
46 };
47
48
49 (function(){
50     var idSeed = 0;
51     var ua = navigator.userAgent.toLowerCase();
52
53     var isStrict = document.compatMode == "CSS1Compat",
54         isOpera = ua.indexOf("opera") > -1,
55         isSafari = (/webkit|khtml/).test(ua),
56         isFirefox = ua.indexOf("firefox") > -1,
57         isIE = ua.indexOf("msie") > -1,
58         isIE7 = ua.indexOf("msie 7") > -1,
59         isIE11 = /trident.*rv\:11\./.test(ua),
60         isEdge = ua.indexOf("edge") > -1,
61         isGecko = !isSafari && ua.indexOf("gecko") > -1,
62         isBorderBox = isIE && !isStrict,
63         isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
64         isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
65         isLinux = (ua.indexOf("linux") != -1),
66         isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
67         isIOS = /iphone|ipad/.test(ua),
68         isAndroid = /android/.test(ua),
69         isTouch =  (function() {
70             try {
71                 if (ua.indexOf('chrome') != -1 && ua.indexOf('android') == -1) {
72                     window.addEventListener('touchstart', function __set_has_touch__ () {
73                         Roo.isTouch = true;
74                         window.removeEventListener('touchstart', __set_has_touch__);
75                     });
76                     return false; // no touch on chrome!?
77                 }
78                 document.createEvent("TouchEvent");  
79                 return true;  
80             } catch (e) {  
81                 return false;  
82             } 
83             
84         })();
85     // remove css image flicker
86         if(isIE && !isIE7){
87         try{
88             document.execCommand("BackgroundImageCache", false, true);
89         }catch(e){}
90     }
91     
92     Roo.apply(Roo, {
93         /**
94          * True if the browser is in strict mode
95          * @type Boolean
96          */
97         isStrict : isStrict,
98         /**
99          * True if the page is running over SSL
100          * @type Boolean
101          */
102         isSecure : isSecure,
103         /**
104          * True when the document is fully initialized and ready for action
105          * @type Boolean
106          */
107         isReady : false,
108         /**
109          * Turn on debugging output (currently only the factory uses this)
110          * @type Boolean
111          */
112         
113         debug: false,
114
115         /**
116          * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
117          * @type Boolean
118          */
119         enableGarbageCollector : true,
120
121         /**
122          * True to automatically purge event listeners after uncaching an element (defaults to false).
123          * Note: this only happens if enableGarbageCollector is true.
124          * @type Boolean
125          */
126         enableListenerCollection:false,
127
128         /**
129          * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
130          * the IE insecure content warning (defaults to javascript:false).
131          * @type String
132          */
133         SSL_SECURE_URL : "javascript:false",
134
135         /**
136          * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
137          * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
138          * @type String
139          */
140         BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
141
142         emptyFn : function(){},
143         
144         /**
145          * Copies all the properties of config to obj if they don't already exist.
146          * @param {Object} obj The receiver of the properties
147          * @param {Object} config The source of the properties
148          * @return {Object} returns obj
149          */
150         applyIf : function(o, c){
151             if(o && c){
152                 for(var p in c){
153                     if(typeof o[p] == "undefined"){ o[p] = c[p]; }
154                 }
155             }
156             return o;
157         },
158
159         /**
160          * Applies event listeners to elements by selectors when the document is ready.
161          * The event name is specified with an @ suffix.
162 <pre><code>
163 Roo.addBehaviors({
164    // add a listener for click on all anchors in element with id foo
165    '#foo a@click' : function(e, t){
166        // do something
167    },
168
169    // add the same listener to multiple selectors (separated by comma BEFORE the @)
170    '#foo a, #bar span.some-class@mouseover' : function(){
171        // do something
172    }
173 });
174 </code></pre>
175          * @param {Object} obj The list of behaviors to apply
176          */
177         addBehaviors : function(o){
178             if(!Roo.isReady){
179                 Roo.onReady(function(){
180                     Roo.addBehaviors(o);
181                 });
182                 return;
183             }
184             var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
185             for(var b in o){
186                 var parts = b.split('@');
187                 if(parts[1]){ // for Object prototype breakers
188                     var s = parts[0];
189                     if(!cache[s]){
190                         cache[s] = Roo.select(s);
191                     }
192                     cache[s].on(parts[1], o[b]);
193                 }
194             }
195             cache = null;
196         },
197
198         /**
199          * Generates unique ids. If the element already has an id, it is unchanged
200          * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
201          * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
202          * @return {String} The generated Id.
203          */
204         id : function(el, prefix){
205             prefix = prefix || "roo-gen";
206             el = Roo.getDom(el);
207             var id = prefix + (++idSeed);
208             return el ? (el.id ? el.id : (el.id = id)) : id;
209         },
210          
211        
212         /**
213          * Extends one class with another class and optionally overrides members with the passed literal. This class
214          * also adds the function "override()" to the class that can be used to override
215          * members on an instance.
216          * @param {Object} subclass The class inheriting the functionality
217          * @param {Object} superclass The class being extended
218          * @param {Object} overrides (optional) A literal with members
219          * @method extend
220          */
221         extend : function(){
222             // inline overrides
223             var io = function(o){
224                 for(var m in o){
225                     this[m] = o[m];
226                 }
227             };
228             return function(sb, sp, overrides){
229                 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
230                     overrides = sp;
231                     sp = sb;
232                     sb = function(){sp.apply(this, arguments);};
233                 }
234                 var F = function(){}, sbp, spp = sp.prototype;
235                 F.prototype = spp;
236                 sbp = sb.prototype = new F();
237                 sbp.constructor=sb;
238                 sb.superclass=spp;
239                 
240                 if(spp.constructor == Object.prototype.constructor){
241                     spp.constructor=sp;
242                    
243                 }
244                 
245                 sb.override = function(o){
246                     Roo.override(sb, o);
247                 };
248                 sbp.override = io;
249                 Roo.override(sb, overrides);
250                 return sb;
251             };
252         }(),
253
254         /**
255          * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
256          * Usage:<pre><code>
257 Roo.override(MyClass, {
258     newMethod1: function(){
259         // etc.
260     },
261     newMethod2: function(foo){
262         // etc.
263     }
264 });
265  </code></pre>
266          * @param {Object} origclass The class to override
267          * @param {Object} overrides The list of functions to add to origClass.  This should be specified as an object literal
268          * containing one or more methods.
269          * @method override
270          */
271         override : function(origclass, overrides){
272             if(overrides){
273                 var p = origclass.prototype;
274                 for(var method in overrides){
275                     p[method] = overrides[method];
276                 }
277             }
278         },
279         /**
280          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
281          * <pre><code>
282 Roo.namespace('Company', 'Company.data');
283 Company.Widget = function() { ... }
284 Company.data.CustomStore = function(config) { ... }
285 </code></pre>
286          * @param {String} namespace1
287          * @param {String} namespace2
288          * @param {String} etc
289          * @method namespace
290          */
291         namespace : function(){
292             var a=arguments, o=null, i, j, d, rt;
293             for (i=0; i<a.length; ++i) {
294                 d=a[i].split(".");
295                 rt = d[0];
296                 /** eval:var:o */
297                 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
298                 for (j=1; j<d.length; ++j) {
299                     o[d[j]]=o[d[j]] || {};
300                     o=o[d[j]];
301                 }
302             }
303         },
304         /**
305          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
306          * <pre><code>
307 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
308 Roo.factory(conf, Roo.data);
309 </code></pre>
310          * @param {String} classname
311          * @param {String} namespace (optional)
312          * @method factory
313          */
314          
315         factory : function(c, ns)
316         {
317             // no xtype, no ns or c.xns - or forced off by c.xns
318             if (!c.xtype   || (!ns && !c.xns) ||  (c.xns === false)) { // not enough info...
319                 return c;
320             }
321             ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
322             if (c.constructor == ns[c.xtype]) {// already created...
323                 return c;
324             }
325             if (ns[c.xtype]) {
326                 if (Roo.debug) { Roo.log("Roo.Factory(" + c.xtype + ")"); }
327                 var ret = new ns[c.xtype](c);
328                 ret.xns = false;
329                 return ret;
330             }
331             c.xns = false; // prevent recursion..
332             return c;
333         },
334          /**
335          * Logs to console if it can.
336          *
337          * @param {String|Object} string
338          * @method log
339          */
340         log : function(s)
341         {
342             if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
343                 return; // alerT?
344             }
345             
346             console.log(s);
347         },
348         /**
349          * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2".  Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
350          * @param {Object} o
351          * @return {String}
352          */
353         urlEncode : function(o){
354             if(!o){
355                 return "";
356             }
357             var buf = [];
358             for(var key in o){
359                 var ov = o[key], k = Roo.encodeURIComponent(key);
360                 var type = typeof ov;
361                 if(type == 'undefined'){
362                     buf.push(k, "=&");
363                 }else if(type != "function" && type != "object"){
364                     buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
365                 }else if(ov instanceof Array){
366                     if (ov.length) {
367                             for(var i = 0, len = ov.length; i < len; i++) {
368                                 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
369                             }
370                         } else {
371                             buf.push(k, "=&");
372                         }
373                 }
374             }
375             buf.pop();
376             return buf.join("");
377         },
378          /**
379          * Safe version of encodeURIComponent
380          * @param {String} data 
381          * @return {String} 
382          */
383         
384         encodeURIComponent : function (data)
385         {
386             try {
387                 return encodeURIComponent(data);
388             } catch(e) {} // should be an uri encode error.
389             
390             if (data == '' || data == null){
391                return '';
392             }
393             // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
394             function nibble_to_hex(nibble){
395                 var chars = '0123456789ABCDEF';
396                 return chars.charAt(nibble);
397             }
398             data = data.toString();
399             var buffer = '';
400             for(var i=0; i<data.length; i++){
401                 var c = data.charCodeAt(i);
402                 var bs = new Array();
403                 if (c > 0x10000){
404                         // 4 bytes
405                     bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
406                     bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
407                     bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
408                     bs[3] = 0x80 | (c & 0x3F);
409                 }else if (c > 0x800){
410                          // 3 bytes
411                     bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
412                     bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
413                     bs[2] = 0x80 | (c & 0x3F);
414                 }else if (c > 0x80){
415                        // 2 bytes
416                     bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
417                     bs[1] = 0x80 | (c & 0x3F);
418                 }else{
419                         // 1 byte
420                     bs[0] = c;
421                 }
422                 for(var j=0; j<bs.length; j++){
423                     var b = bs[j];
424                     var hex = nibble_to_hex((b & 0xF0) >>> 4) 
425                             + nibble_to_hex(b &0x0F);
426                     buffer += '%'+hex;
427                }
428             }
429             return buffer;    
430              
431         },
432
433         /**
434          * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
435          * @param {String} string
436          * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
437          * @return {Object} A literal with members
438          */
439         urlDecode : function(string, overwrite){
440             if(!string || !string.length){
441                 return {};
442             }
443             var obj = {};
444             var pairs = string.split('&');
445             var pair, name, value;
446             for(var i = 0, len = pairs.length; i < len; i++){
447                 pair = pairs[i].split('=');
448                 name = decodeURIComponent(pair[0]);
449                 value = decodeURIComponent(pair[1]);
450                 if(overwrite !== true){
451                     if(typeof obj[name] == "undefined"){
452                         obj[name] = value;
453                     }else if(typeof obj[name] == "string"){
454                         obj[name] = [obj[name]];
455                         obj[name].push(value);
456                     }else{
457                         obj[name].push(value);
458                     }
459                 }else{
460                     obj[name] = value;
461                 }
462             }
463             return obj;
464         },
465
466         /**
467          * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
468          * passed array is not really an array, your function is called once with it.
469          * The supplied function is called with (Object item, Number index, Array allItems).
470          * @param {Array/NodeList/Mixed} array
471          * @param {Function} fn
472          * @param {Object} scope
473          */
474         each : function(array, fn, scope){
475             if(typeof array.length == "undefined" || typeof array == "string"){
476                 array = [array];
477             }
478             for(var i = 0, len = array.length; i < len; i++){
479                 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
480             }
481         },
482
483         // deprecated
484         combine : function(){
485             var as = arguments, l = as.length, r = [];
486             for(var i = 0; i < l; i++){
487                 var a = as[i];
488                 if(a instanceof Array){
489                     r = r.concat(a);
490                 }else if(a.length !== undefined && !a.substr){
491                     r = r.concat(Array.prototype.slice.call(a, 0));
492                 }else{
493                     r.push(a);
494                 }
495             }
496             return r;
497         },
498
499         /**
500          * Escapes the passed string for use in a regular expression
501          * @param {String} str
502          * @return {String}
503          */
504         escapeRe : function(s) {
505             return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
506         },
507
508         // internal
509         callback : function(cb, scope, args, delay){
510             if(typeof cb == "function"){
511                 if(delay){
512                     cb.defer(delay, scope, args || []);
513                 }else{
514                     cb.apply(scope, args || []);
515                 }
516             }
517         },
518
519         /**
520          * Return the dom node for the passed string (id), dom node, or Roo.Element
521          * @param {String/HTMLElement/Roo.Element} el
522          * @return HTMLElement
523          */
524         getDom : function(el){
525             if(!el){
526                 return null;
527             }
528             return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
529         },
530
531         /**
532         * Shorthand for {@link Roo.ComponentMgr#get}
533         * @param {String} id
534         * @return Roo.Component
535         */
536         getCmp : function(id){
537             return Roo.ComponentMgr.get(id);
538         },
539          
540         num : function(v, defaultValue){
541             if(typeof v != 'number'){
542                 return defaultValue;
543             }
544             return v;
545         },
546
547         destroy : function(){
548             for(var i = 0, a = arguments, len = a.length; i < len; i++) {
549                 var as = a[i];
550                 if(as){
551                     if(as.dom){
552                         as.removeAllListeners();
553                         as.remove();
554                         continue;
555                     }
556                     if(typeof as.purgeListeners == 'function'){
557                         as.purgeListeners();
558                     }
559                     if(typeof as.destroy == 'function'){
560                         as.destroy();
561                     }
562                 }
563             }
564         },
565
566         // inpired by a similar function in mootools library
567         /**
568          * Returns the type of object that is passed in. If the object passed in is null or undefined it
569          * return false otherwise it returns one of the following values:<ul>
570          * <li><b>string</b>: If the object passed is a string</li>
571          * <li><b>number</b>: If the object passed is a number</li>
572          * <li><b>boolean</b>: If the object passed is a boolean value</li>
573          * <li><b>function</b>: If the object passed is a function reference</li>
574          * <li><b>object</b>: If the object passed is an object</li>
575          * <li><b>array</b>: If the object passed is an array</li>
576          * <li><b>regexp</b>: If the object passed is a regular expression</li>
577          * <li><b>element</b>: If the object passed is a DOM Element</li>
578          * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
579          * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
580          * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
581          * @param {Mixed} object
582          * @return {String}
583          */
584         type : function(o){
585             if(o === undefined || o === null){
586                 return false;
587             }
588             if(o.htmlElement){
589                 return 'element';
590             }
591             var t = typeof o;
592             if(t == 'object' && o.nodeName) {
593                 switch(o.nodeType) {
594                     case 1: return 'element';
595                     case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
596                 }
597             }
598             if(t == 'object' || t == 'function') {
599                 switch(o.constructor) {
600                     case Array: return 'array';
601                     case RegExp: return 'regexp';
602                 }
603                 if(typeof o.length == 'number' && typeof o.item == 'function') {
604                     return 'nodelist';
605                 }
606             }
607             return t;
608         },
609
610         /**
611          * Returns true if the passed value is null, undefined or an empty string (optional).
612          * @param {Mixed} value The value to test
613          * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
614          * @return {Boolean}
615          */
616         isEmpty : function(v, allowBlank){
617             return v === null || v === undefined || (!allowBlank ? v === '' : false);
618         },
619         
620         /** @type Boolean */
621         isOpera : isOpera,
622         /** @type Boolean */
623         isSafari : isSafari,
624         /** @type Boolean */
625         isFirefox : isFirefox,
626         /** @type Boolean */
627         isIE : isIE,
628         /** @type Boolean */
629         isIE7 : isIE7,
630         /** @type Boolean */
631         isIE11 : isIE11,
632         /** @type Boolean */
633         isEdge : isEdge,
634         /** @type Boolean */
635         isGecko : isGecko,
636         /** @type Boolean */
637         isBorderBox : isBorderBox,
638         /** @type Boolean */
639         isWindows : isWindows,
640         /** @type Boolean */
641         isLinux : isLinux,
642         /** @type Boolean */
643         isMac : isMac,
644         /** @type Boolean */
645         isIOS : isIOS,
646         /** @type Boolean */
647         isAndroid : isAndroid,
648         /** @type Boolean */
649         isTouch : isTouch,
650
651         /**
652          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
653          * you may want to set this to true.
654          * @type Boolean
655          */
656         useShims : ((isIE && !isIE7) || (isGecko && isMac)),
657         
658         
659                 
660         /**
661          * Selects a single element as a Roo Element
662          * This is about as close as you can get to jQuery's $('do crazy stuff')
663          * @param {String} selector The selector/xpath query
664          * @param {Node} root (optional) The start of the query (defaults to document).
665          * @return {Roo.Element}
666          */
667         selectNode : function(selector, root) 
668         {
669             var node = Roo.DomQuery.selectNode(selector,root);
670             return node ? Roo.get(node) : new Roo.Element(false);
671         },
672                 /**
673                  * Find the current bootstrap width Grid size
674                  * Note xs is the default for smaller.. - this is currently used by grids to render correct columns
675                  * @returns {String} (xs|sm|md|lg|xl)
676                  */
677                 
678                 getGridSize : function()
679                 {
680                         var w = Roo.lib.Dom.getViewWidth();
681                         switch(true) {
682                                 case w > 1200:
683                                         return 'xl';
684                                 case w > 992:
685                                         return 'lg';
686                                 case w > 768:
687                                         return 'md';
688                                 case w > 576:
689                                         return 'sm';
690                                 default:
691                                         return 'xs'
692                         }
693                         
694                 }
695         
696     });
697
698
699 })();
700
701 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
702                 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
703                 "Roo.app", "Roo.ux" 
704                );
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  * Originally based of this code... - refactored for Roo...
4902  * https://github.com/aaalsaleh/undo-manager
4903  
4904  * undo-manager.js
4905  * @author  Abdulrahman Alsaleh 
4906  * @copyright 2015 Abdulrahman Alsaleh 
4907  * @license  MIT License (c) 
4908  *
4909  * Hackily modifyed by alan@roojs.com
4910  *
4911  *
4912  *  
4913  *
4914  *  TOTALLY UNTESTED...
4915  *
4916  *  Documentation to be done....
4917  */
4918  
4919
4920 /**
4921 * @class Roo.lib.UndoManager
4922 * An undo manager implementation in JavaScript. It follows the W3C UndoManager and DOM Transaction
4923 * Draft and the undocumented and disabled Mozilla Firefox's UndoManager implementation.
4924
4925  * Usage:
4926  * <pre><code>
4927
4928
4929 editor.undoManager = new Roo.lib.UndoManager(1000, editor);
4930  
4931 </code></pre>
4932
4933 * For more information see this blog post with examples:
4934 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4935      - Create Elements using DOM, HTML fragments and Templates</a>. 
4936 * @constructor
4937 * @param {Number} limit how far back to go ... use 1000?
4938 * @param {Object} scope usually use document..
4939 */
4940
4941 Roo.lib.UndoManager = function (limit, undoScopeHost)
4942 {
4943     this.stack = [];
4944     this.limit = limit;
4945     this.scope = undoScopeHost;
4946     this.fireEvent = typeof CustomEvent != 'undefined' && undoScopeHost && undoScopeHost.dispatchEvent;
4947     if (this.fireEvent) {
4948         this.bindEvents();
4949     }
4950     this.reset();
4951     
4952 };
4953         
4954 Roo.lib.UndoManager.prototype = {
4955     
4956     limit : false,
4957     stack : false,
4958     scope :  false,
4959     fireEvent : false,
4960     position : 0,
4961     length : 0,
4962     
4963     
4964      /**
4965      * To push and execute a transaction, the method undoManager.transact
4966      * must be called by passing a transaction object as the first argument, and a merge
4967      * flag as the second argument. A transaction object has the following properties:
4968      *
4969      * Usage:
4970 <pre><code>
4971 undoManager.transact({
4972     label: 'Typing',
4973     execute: function() { ... },
4974     undo: function() { ... },
4975     // redo same as execute
4976     redo: function() { this.execute(); }
4977 }, false);
4978
4979 // merge transaction
4980 undoManager.transact({
4981     label: 'Typing',
4982     execute: function() { ... },  // this will be run...
4983     undo: function() { ... }, // what to do when undo is run.
4984     // redo same as execute
4985     redo: function() { this.execute(); }
4986 }, true); 
4987 </code></pre> 
4988      *
4989      * 
4990      * @param {Object} transaction The transaction to add to the stack.
4991      * @return {String} The HTML fragment
4992      */
4993     
4994     
4995     transact : function (transaction, merge)
4996     {
4997         if (arguments.length < 2) {
4998             throw new TypeError('Not enough arguments to UndoManager.transact.');
4999         }
5000
5001         transaction.execute();
5002
5003         this.stack.splice(0, this.position);
5004         if (merge && this.length) {
5005             this.stack[0].push(transaction);
5006         } else {
5007             this.stack.unshift([transaction]);
5008         }
5009     
5010         this.position = 0;
5011
5012         if (this.limit && this.stack.length > this.limit) {
5013             this.length = this.stack.length = this.limit;
5014         } else {
5015             this.length = this.stack.length;
5016         }
5017
5018         if (this.fireEvent) {
5019             this.scope.dispatchEvent(
5020                 new CustomEvent('DOMTransaction', {
5021                     detail: {
5022                         transactions: this.stack[0].slice()
5023                     },
5024                     bubbles: true,
5025                     cancelable: false
5026                 })
5027             );
5028         }
5029         
5030         Roo.log("transaction: pos:" + this.position + " len: " + this.length + " slen:" + this.stack.length);
5031       
5032         
5033     },
5034
5035     undo : function ()
5036     {
5037         Roo.log("undo: pos:" + this.position + " len: " + this.length + " slen:" + this.stack.length);
5038         
5039         if (this.position < this.length) {
5040             for (var i = this.stack[this.position].length - 1; i >= 0; i--) {
5041                 this.stack[this.position][i].undo();
5042             }
5043             this.position++;
5044
5045             if (this.fireEvent) {
5046                 this.scope.dispatchEvent(
5047                     new CustomEvent('undo', {
5048                         detail: {
5049                             transactions: this.stack[this.position - 1].slice()
5050                         },
5051                         bubbles: true,
5052                         cancelable: false
5053                     })
5054                 );
5055             }
5056         }
5057     },
5058
5059     redo : function ()
5060     {
5061         if (this.position > 0) {
5062             for (var i = 0, n = this.stack[this.position - 1].length; i < n; i++) {
5063                 this.stack[this.position - 1][i].redo();
5064             }
5065             this.position--;
5066
5067             if (this.fireEvent) {
5068                 this.scope.dispatchEvent(
5069                     new CustomEvent('redo', {
5070                         detail: {
5071                             transactions: this.stack[this.position].slice()
5072                         },
5073                         bubbles: true,
5074                         cancelable: false
5075                     })
5076                 );
5077             }
5078         }
5079     },
5080
5081     item : function (index)
5082     {
5083         if (index >= 0 && index < this.length) {
5084             return this.stack[index].slice();
5085         }
5086         return null;
5087     },
5088
5089     clearUndo : function () {
5090         this.stack.length = this.length = this.position;
5091     },
5092
5093     clearRedo : function () {
5094         this.stack.splice(0, this.position);
5095         this.position = 0;
5096         this.length = this.stack.length;
5097     },
5098     /**
5099      * Reset the undo - probaly done on load to clear all history.
5100      */
5101     reset : function()
5102     {
5103         this.stack = [];
5104         this.position = 0;
5105         this.length = 0;
5106         this.current_html = this.scope.innerHTML;
5107         if (this.timer !== false) {
5108             clearTimeout(this.timer);
5109         }
5110         this.timer = false;
5111         this.merge = false;
5112         this.addEvent();
5113         
5114     },
5115     current_html : '',
5116     timer : false,
5117     merge : false,
5118     
5119     
5120     // this will handle the undo/redo on the element.?
5121     bindEvents : function()
5122     {
5123         var el  = this.scope;
5124         el.undoManager = this;
5125         
5126         
5127         this.scope.addEventListener('keydown', function(e) {
5128             if ((e.ctrlKey || e.metaKey) && e.keyCode === 90) {
5129                 if (e.shiftKey) {
5130                     el.undoManager.redo(); // Ctrl/Command + Shift + Z
5131                 } else {
5132                     el.undoManager.undo(); // Ctrl/Command + Z
5133                 }
5134         
5135                 e.preventDefault();
5136             }
5137         });
5138         /// ignore keyup..
5139         this.scope.addEventListener('keyup', function(e) {
5140             if ((e.ctrlKey || e.metaKey) && e.keyCode === 90) {
5141                 e.preventDefault();
5142             }
5143         });
5144         
5145         
5146         
5147         var t = this;
5148         
5149         el.addEventListener('input', function(e) {
5150             if(el.innerHTML == t.current_html) {
5151                 return;
5152             }
5153             // only record events every second.
5154             if (t.timer !== false) {
5155                clearTimeout(t.timer);
5156                t.timer = false;
5157             }
5158             t.timer = setTimeout(function() { t.merge = false; }, 1000);
5159             
5160             t.addEvent(t.merge);
5161             t.merge = true; // ignore changes happening every second..
5162         });
5163         },
5164     /**
5165      * Manually add an event.
5166      * Normall called without arguements - and it will just get added to the stack.
5167      * 
5168      */
5169     
5170     addEvent : function(merge)
5171     {
5172         Roo.log("undomanager +" + (merge ? 'Y':'n'));
5173         // not sure if this should clear the timer 
5174         merge = typeof(merge) == 'undefined' ? false : merge; 
5175         
5176         this.scope.undoManager.transact({
5177             scope : this.scope,
5178             oldHTML: this.current_html,
5179             newHTML: this.scope.innerHTML,
5180             // nothing to execute (content already changed when input is fired)
5181             execute: function() { },
5182             undo: function() {
5183                 this.scope.innerHTML = this.current_html = this.oldHTML;
5184             },
5185             redo: function() {
5186                 this.scope.innerHTML = this.current_html = this.newHTML;
5187             }
5188         }, false); //merge);
5189         
5190         this.merge = merge;
5191         
5192         this.current_html = this.scope.innerHTML;
5193     }
5194     
5195     
5196      
5197     
5198     
5199     
5200 };
5201 /*
5202  * Based on:
5203  * Ext JS Library 1.1.1
5204  * Copyright(c) 2006-2007, Ext JS, LLC.
5205  *
5206  * Originally Released Under LGPL - original licence link has changed is not relivant.
5207  *
5208  * Fork - LGPL
5209  * <script type="text/javascript">
5210  */
5211
5212
5213 // nasty IE9 hack - what a pile of crap that is..
5214
5215  if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
5216     Range.prototype.createContextualFragment = function (html) {
5217         var doc = window.document;
5218         var container = doc.createElement("div");
5219         container.innerHTML = html;
5220         var frag = doc.createDocumentFragment(), n;
5221         while ((n = container.firstChild)) {
5222             frag.appendChild(n);
5223         }
5224         return frag;
5225     };
5226 }
5227
5228 /**
5229  * @class Roo.DomHelper
5230  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
5231  * 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>.
5232  * @static
5233  */
5234 Roo.DomHelper = function(){
5235     var tempTableEl = null;
5236     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
5237     var tableRe = /^table|tbody|tr|td$/i;
5238     var xmlns = {};
5239     // build as innerHTML where available
5240     /** @ignore */
5241     var createHtml = function(o){
5242         if(typeof o == 'string'){
5243             return o;
5244         }
5245         var b = "";
5246         if(!o.tag){
5247             o.tag = "div";
5248         }
5249         b += "<" + o.tag;
5250         for(var attr in o){
5251             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") { continue; }
5252             if(attr == "style"){
5253                 var s = o["style"];
5254                 if(typeof s == "function"){
5255                     s = s.call();
5256                 }
5257                 if(typeof s == "string"){
5258                     b += ' style="' + s + '"';
5259                 }else if(typeof s == "object"){
5260                     b += ' style="';
5261                     for(var key in s){
5262                         if(typeof s[key] != "function"){
5263                             b += key + ":" + s[key] + ";";
5264                         }
5265                     }
5266                     b += '"';
5267                 }
5268             }else{
5269                 if(attr == "cls"){
5270                     b += ' class="' + o["cls"] + '"';
5271                 }else if(attr == "htmlFor"){
5272                     b += ' for="' + o["htmlFor"] + '"';
5273                 }else{
5274                     b += " " + attr + '="' + o[attr] + '"';
5275                 }
5276             }
5277         }
5278         if(emptyTags.test(o.tag)){
5279             b += "/>";
5280         }else{
5281             b += ">";
5282             var cn = o.children || o.cn;
5283             if(cn){
5284                 //http://bugs.kde.org/show_bug.cgi?id=71506
5285                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
5286                     for(var i = 0, len = cn.length; i < len; i++) {
5287                         b += createHtml(cn[i], b);
5288                     }
5289                 }else{
5290                     b += createHtml(cn, b);
5291                 }
5292             }
5293             if(o.html){
5294                 b += o.html;
5295             }
5296             b += "</" + o.tag + ">";
5297         }
5298         return b;
5299     };
5300
5301     // build as dom
5302     /** @ignore */
5303     var createDom = function(o, parentNode){
5304          
5305         // defininition craeted..
5306         var ns = false;
5307         if (o.ns && o.ns != 'html') {
5308                
5309             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
5310                 xmlns[o.ns] = o.xmlns;
5311                 ns = o.xmlns;
5312             }
5313             if (typeof(xmlns[o.ns]) == 'undefined') {
5314                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
5315             }
5316             ns = xmlns[o.ns];
5317         }
5318         
5319         
5320         if (typeof(o) == 'string') {
5321             return parentNode.appendChild(document.createTextNode(o));
5322         }
5323         o.tag = o.tag || div;
5324         if (o.ns && Roo.isIE) {
5325             ns = false;
5326             o.tag = o.ns + ':' + o.tag;
5327             
5328         }
5329         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
5330         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
5331         for(var attr in o){
5332             
5333             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
5334                     attr == "style" || typeof o[attr] == "function") { continue; }
5335                     
5336             if(attr=="cls" && Roo.isIE){
5337                 el.className = o["cls"];
5338             }else{
5339                 if(useSet) { el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);}
5340                 else { 
5341                     el[attr] = o[attr];
5342                 }
5343             }
5344         }
5345         Roo.DomHelper.applyStyles(el, o.style);
5346         var cn = o.children || o.cn;
5347         if(cn){
5348             //http://bugs.kde.org/show_bug.cgi?id=71506
5349              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
5350                 for(var i = 0, len = cn.length; i < len; i++) {
5351                     createDom(cn[i], el);
5352                 }
5353             }else{
5354                 createDom(cn, el);
5355             }
5356         }
5357         if(o.html){
5358             el.innerHTML = o.html;
5359         }
5360         if(parentNode){
5361            parentNode.appendChild(el);
5362         }
5363         return el;
5364     };
5365
5366     var ieTable = function(depth, s, h, e){
5367         tempTableEl.innerHTML = [s, h, e].join('');
5368         var i = -1, el = tempTableEl;
5369         while(++i < depth && el.firstChild){
5370             el = el.firstChild;
5371         }
5372         return el;
5373     };
5374
5375     // kill repeat to save bytes
5376     var ts = '<table>',
5377         te = '</table>',
5378         tbs = ts+'<tbody>',
5379         tbe = '</tbody>'+te,
5380         trs = tbs + '<tr>',
5381         tre = '</tr>'+tbe;
5382
5383     /**
5384      * @ignore
5385      * Nasty code for IE's broken table implementation
5386      */
5387     var insertIntoTable = function(tag, where, el, html){
5388         if(!tempTableEl){
5389             tempTableEl = document.createElement('div');
5390         }
5391         var node;
5392         var before = null;
5393         if(tag == 'td'){
5394             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
5395                 return;
5396             }
5397             if(where == 'beforebegin'){
5398                 before = el;
5399                 el = el.parentNode;
5400             } else{
5401                 before = el.nextSibling;
5402                 el = el.parentNode;
5403             }
5404             node = ieTable(4, trs, html, tre);
5405         }
5406         else if(tag == 'tr'){
5407             if(where == 'beforebegin'){
5408                 before = el;
5409                 el = el.parentNode;
5410                 node = ieTable(3, tbs, html, tbe);
5411             } else if(where == 'afterend'){
5412                 before = el.nextSibling;
5413                 el = el.parentNode;
5414                 node = ieTable(3, tbs, html, tbe);
5415             } else{ // INTO a TR
5416                 if(where == 'afterbegin'){
5417                     before = el.firstChild;
5418                 }
5419                 node = ieTable(4, trs, html, tre);
5420             }
5421         } else if(tag == 'tbody'){
5422             if(where == 'beforebegin'){
5423                 before = el;
5424                 el = el.parentNode;
5425                 node = ieTable(2, ts, html, te);
5426             } else if(where == 'afterend'){
5427                 before = el.nextSibling;
5428                 el = el.parentNode;
5429                 node = ieTable(2, ts, html, te);
5430             } else{
5431                 if(where == 'afterbegin'){
5432                     before = el.firstChild;
5433                 }
5434                 node = ieTable(3, tbs, html, tbe);
5435             }
5436         } else{ // TABLE
5437             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
5438                 return;
5439             }
5440             if(where == 'afterbegin'){
5441                 before = el.firstChild;
5442             }
5443             node = ieTable(2, ts, html, te);
5444         }
5445         el.insertBefore(node, before);
5446         return node;
5447     };
5448     
5449     // this is a bit like the react update code...
5450     // 
5451     
5452     var updateNode = function(from, to)
5453     {
5454         // should we handle non-standard elements?
5455         Roo.log(["UpdateNode" , from, to]);
5456         if (from.nodeType != to.nodeType) {
5457             Roo.log(["ReplaceChild - mismatch notType" , to, from ]);
5458             from.parentNode.replaceChild(to, from);
5459         }
5460         
5461         if (from.nodeType == 3) {
5462             // assume it's text?!
5463             if (from.data == to.data) {
5464                 return;
5465             }
5466             from.data = to.data;
5467             return;
5468         }
5469         
5470         // assume 'to' doesnt have '1/3 nodetypes!
5471         if (from.nodeType !=1 || from.tagName != to.tagName) {
5472             Roo.log(["ReplaceChild" , from, to ]);
5473             from.parentNode.replaceChild(to, from);
5474             return;
5475         }
5476         // compare attributes
5477         var ar = Array.from(from.attributes);
5478         for(var i = 0; i< ar.length;i++) {
5479             if (to.hasAttribute(ar[i].name)) {
5480                 continue;
5481             }
5482             if (ar[i].name == 'id') { // always keep ids?
5483                 continue;
5484             }
5485             from.removeAttribute(ar[i].name);
5486         }
5487         ar = to.attributes;
5488         for(var i = 0; i< ar.length;i++) {
5489             if (from.getAttribute(ar[i].name) == to.getAttribute(ar[i].name)) {
5490                 continue;
5491             }
5492             from.setAttribute(ar[i].name, to.getAttribute(ar[i].name));
5493         }
5494         // children
5495         var far = Array.from(from.childNodes);
5496         var tar = Array.from(to.childNodes);
5497         // if the lengths are different.. then it's probably a editable content change, rather than
5498         // a change of the block definition..
5499         
5500         // this did notwork , as our rebuilt nodes did not include ID's so did not match at all.
5501          /*if (from.innerHTML == to.innerHTML) {
5502             return;
5503         }
5504         if (far.length != tar.length) {
5505             from.innerHTML = to.innerHTML;
5506             return;
5507         }
5508         */
5509         
5510         for(var i = 0; i < Math.max(tar.length, far.length); i++) {
5511             if (i >= far.length) {
5512                 from.appendChild(tar[i]);
5513                 Roo.log(["add", tar[i]]);
5514                 
5515             } else if ( i  >= tar.length) {
5516                 from.removeChild(far[i]);
5517                 Roo.log(["remove", far[i]]);
5518             } else {
5519                 
5520                 updateNode(far[i], tar[i]);
5521             }    
5522         }
5523         
5524         
5525         
5526         
5527     };
5528     
5529     
5530
5531     return {
5532         /** True to force the use of DOM instead of html fragments @type Boolean */
5533         useDom : false,
5534     
5535         /**
5536          * Returns the markup for the passed Element(s) config
5537          * @param {Object} o The Dom object spec (and children)
5538          * @return {String}
5539          */
5540         markup : function(o){
5541             return createHtml(o);
5542         },
5543     
5544         /**
5545          * Applies a style specification to an element
5546          * @param {String/HTMLElement} el The element to apply styles to
5547          * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
5548          * a function which returns such a specification.
5549          */
5550         applyStyles : function(el, styles){
5551             if(styles){
5552                el = Roo.fly(el);
5553                if(typeof styles == "string"){
5554                    var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
5555                    var matches;
5556                    while ((matches = re.exec(styles)) != null){
5557                        el.setStyle(matches[1], matches[2]);
5558                    }
5559                }else if (typeof styles == "object"){
5560                    for (var style in styles){
5561                       el.setStyle(style, styles[style]);
5562                    }
5563                }else if (typeof styles == "function"){
5564                     Roo.DomHelper.applyStyles(el, styles.call());
5565                }
5566             }
5567         },
5568     
5569         /**
5570          * Inserts an HTML fragment into the Dom
5571          * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
5572          * @param {HTMLElement} el The context element
5573          * @param {String} html The HTML fragmenet
5574          * @return {HTMLElement} The new node
5575          */
5576         insertHtml : function(where, el, html){
5577             where = where.toLowerCase();
5578             if(el.insertAdjacentHTML){
5579                 if(tableRe.test(el.tagName)){
5580                     var rs;
5581                     if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
5582                         return rs;
5583                     }
5584                 }
5585                 switch(where){
5586                     case "beforebegin":
5587                         el.insertAdjacentHTML('BeforeBegin', html);
5588                         return el.previousSibling;
5589                     case "afterbegin":
5590                         el.insertAdjacentHTML('AfterBegin', html);
5591                         return el.firstChild;
5592                     case "beforeend":
5593                         el.insertAdjacentHTML('BeforeEnd', html);
5594                         return el.lastChild;
5595                     case "afterend":
5596                         el.insertAdjacentHTML('AfterEnd', html);
5597                         return el.nextSibling;
5598                 }
5599                 throw 'Illegal insertion point -> "' + where + '"';
5600             }
5601             var range = el.ownerDocument.createRange();
5602             var frag;
5603             switch(where){
5604                  case "beforebegin":
5605                     range.setStartBefore(el);
5606                     frag = range.createContextualFragment(html);
5607                     el.parentNode.insertBefore(frag, el);
5608                     return el.previousSibling;
5609                  case "afterbegin":
5610                     if(el.firstChild){
5611                         range.setStartBefore(el.firstChild);
5612                         frag = range.createContextualFragment(html);
5613                         el.insertBefore(frag, el.firstChild);
5614                         return el.firstChild;
5615                     }else{
5616                         el.innerHTML = html;
5617                         return el.firstChild;
5618                     }
5619                 case "beforeend":
5620                     if(el.lastChild){
5621                         range.setStartAfter(el.lastChild);
5622                         frag = range.createContextualFragment(html);
5623                         el.appendChild(frag);
5624                         return el.lastChild;
5625                     }else{
5626                         el.innerHTML = html;
5627                         return el.lastChild;
5628                     }
5629                 case "afterend":
5630                     range.setStartAfter(el);
5631                     frag = range.createContextualFragment(html);
5632                     el.parentNode.insertBefore(frag, el.nextSibling);
5633                     return el.nextSibling;
5634                 }
5635                 throw 'Illegal insertion point -> "' + where + '"';
5636         },
5637     
5638         /**
5639          * Creates new Dom element(s) and inserts them before el
5640          * @param {String/HTMLElement/Element} el The context element
5641          * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5642          * @param {Boolean} returnElement (optional) true to return a Roo.Element
5643          * @return {HTMLElement/Roo.Element} The new node
5644          */
5645         insertBefore : function(el, o, returnElement){
5646             return this.doInsert(el, o, returnElement, "beforeBegin");
5647         },
5648     
5649         /**
5650          * Creates new Dom element(s) and inserts them after el
5651          * @param {String/HTMLElement/Element} el The context element
5652          * @param {Object} o The Dom object spec (and children)
5653          * @param {Boolean} returnElement (optional) true to return a Roo.Element
5654          * @return {HTMLElement/Roo.Element} The new node
5655          */
5656         insertAfter : function(el, o, returnElement){
5657             return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
5658         },
5659     
5660         /**
5661          * Creates new Dom element(s) and inserts them as the first child of el
5662          * @param {String/HTMLElement/Element} el The context element
5663          * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5664          * @param {Boolean} returnElement (optional) true to return a Roo.Element
5665          * @return {HTMLElement/Roo.Element} The new node
5666          */
5667         insertFirst : function(el, o, returnElement){
5668             return this.doInsert(el, o, returnElement, "afterBegin");
5669         },
5670     
5671         // private
5672         doInsert : function(el, o, returnElement, pos, sibling){
5673             el = Roo.getDom(el);
5674             var newNode;
5675             if(this.useDom || o.ns){
5676                 newNode = createDom(o, null);
5677                 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
5678             }else{
5679                 var html = createHtml(o);
5680                 newNode = this.insertHtml(pos, el, html);
5681             }
5682             return returnElement ? Roo.get(newNode, true) : newNode;
5683         },
5684     
5685         /**
5686          * Creates new Dom element(s) and appends them to el
5687          * @param {String/HTMLElement/Element} el The context element
5688          * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5689          * @param {Boolean} returnElement (optional) true to return a Roo.Element
5690          * @return {HTMLElement/Roo.Element} The new node
5691          */
5692         append : function(el, o, returnElement){
5693             el = Roo.getDom(el);
5694             var newNode;
5695             if(this.useDom || o.ns){
5696                 newNode = createDom(o, null);
5697                 el.appendChild(newNode);
5698             }else{
5699                 var html = createHtml(o);
5700                 newNode = this.insertHtml("beforeEnd", el, html);
5701             }
5702             return returnElement ? Roo.get(newNode, true) : newNode;
5703         },
5704     
5705         /**
5706          * Creates new Dom element(s) and overwrites the contents of el with them
5707          * @param {String/HTMLElement/Element} el The context element
5708          * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5709          * @param {Boolean} returnElement (optional) true to return a Roo.Element
5710          * @return {HTMLElement/Roo.Element} The new node
5711          */
5712         overwrite : function(el, o, returnElement)
5713         {
5714             el = Roo.getDom(el);
5715             if (o.ns) {
5716               
5717                 while (el.childNodes.length) {
5718                     el.removeChild(el.firstChild);
5719                 }
5720                 createDom(o, el);
5721             } else {
5722                 el.innerHTML = createHtml(o);   
5723             }
5724             
5725             return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
5726         },
5727     
5728         /**
5729          * Creates a new Roo.DomHelper.Template from the Dom object spec
5730          * @param {Object} o The Dom object spec (and children)
5731          * @return {Roo.DomHelper.Template} The new template
5732          */
5733         createTemplate : function(o){
5734             var html = createHtml(o);
5735             return new Roo.Template(html);
5736         },
5737          /**
5738          * Updates the first element with the spec from the o (replacing if necessary)
5739          * This iterates through the children, and updates attributes / children etc..
5740          * @param {String/HTMLElement/Element} el The context element
5741          * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5742          */
5743         
5744         update : function(el, o)
5745         {
5746             updateNode(Roo.getDom(el), createDom(o));
5747             
5748         }
5749         
5750         
5751     };
5752 }();
5753 /*
5754  * Based on:
5755  * Ext JS Library 1.1.1
5756  * Copyright(c) 2006-2007, Ext JS, LLC.
5757  *
5758  * Originally Released Under LGPL - original licence link has changed is not relivant.
5759  *
5760  * Fork - LGPL
5761  * <script type="text/javascript">
5762  */
5763  
5764 /**
5765 * @class Roo.Template
5766 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
5767 * For a list of available format functions, see {@link Roo.util.Format}.<br />
5768 * Usage:
5769 <pre><code>
5770 var t = new Roo.Template({
5771     html :  '&lt;div name="{id}"&gt;' + 
5772         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
5773         '&lt;/div&gt;',
5774     myformat: function (value, allValues) {
5775         return 'XX' + value;
5776     }
5777 });
5778 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
5779 </code></pre>
5780 * For more information see this blog post with examples:
5781 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
5782      - Create Elements using DOM, HTML fragments and Templates</a>. 
5783 * @constructor
5784 * @param {Object} cfg - Configuration object.
5785 */
5786 Roo.Template = function(cfg){
5787     // BC!
5788     if(cfg instanceof Array){
5789         cfg = cfg.join("");
5790     }else if(arguments.length > 1){
5791         cfg = Array.prototype.join.call(arguments, "");
5792     }
5793     
5794     
5795     if (typeof(cfg) == 'object') {
5796         Roo.apply(this,cfg)
5797     } else {
5798         // bc
5799         this.html = cfg;
5800     }
5801     if (this.url) {
5802         this.load();
5803     }
5804     
5805 };
5806 Roo.Template.prototype = {
5807     
5808     /**
5809      * @cfg {Function} onLoad Called after the template has been loaded and complied (usually from a remove source)
5810      */
5811     onLoad : false,
5812     
5813     
5814     /**
5815      * @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..
5816      *                    it should be fixed so that template is observable...
5817      */
5818     url : false,
5819     /**
5820      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
5821      */
5822     html : '',
5823     
5824     
5825     compiled : false,
5826     loaded : false,
5827     /**
5828      * Returns an HTML fragment of this template with the specified values applied.
5829      * @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'})
5830      * @return {String} The HTML fragment
5831      */
5832     
5833    
5834     
5835     applyTemplate : function(values){
5836         //Roo.log(["applyTemplate", values]);
5837         try {
5838            
5839             if(this.compiled){
5840                 return this.compiled(values);
5841             }
5842             var useF = this.disableFormats !== true;
5843             var fm = Roo.util.Format, tpl = this;
5844             var fn = function(m, name, format, args){
5845                 if(format && useF){
5846                     if(format.substr(0, 5) == "this."){
5847                         return tpl.call(format.substr(5), values[name], values);
5848                     }else{
5849                         if(args){
5850                             // quoted values are required for strings in compiled templates, 
5851                             // but for non compiled we need to strip them
5852                             // quoted reversed for jsmin
5853                             var re = /^\s*['"](.*)["']\s*$/;
5854                             args = args.split(',');
5855                             for(var i = 0, len = args.length; i < len; i++){
5856                                 args[i] = args[i].replace(re, "$1");
5857                             }
5858                             args = [values[name]].concat(args);
5859                         }else{
5860                             args = [values[name]];
5861                         }
5862                         return fm[format].apply(fm, args);
5863                     }
5864                 }else{
5865                     return values[name] !== undefined ? values[name] : "";
5866                 }
5867             };
5868             return this.html.replace(this.re, fn);
5869         } catch (e) {
5870             Roo.log(e);
5871             throw e;
5872         }
5873          
5874     },
5875     
5876     loading : false,
5877       
5878     load : function ()
5879     {
5880          
5881         if (this.loading) {
5882             return;
5883         }
5884         var _t = this;
5885         
5886         this.loading = true;
5887         this.compiled = false;
5888         
5889         var cx = new Roo.data.Connection();
5890         cx.request({
5891             url : this.url,
5892             method : 'GET',
5893             success : function (response) {
5894                 _t.loading = false;
5895                 _t.url = false;
5896                 
5897                 _t.set(response.responseText,true);
5898                 _t.loaded = true;
5899                 if (_t.onLoad) {
5900                     _t.onLoad();
5901                 }
5902              },
5903             failure : function(response) {
5904                 Roo.log("Template failed to load from " + _t.url);
5905                 _t.loading = false;
5906             }
5907         });
5908     },
5909
5910     /**
5911      * Sets the HTML used as the template and optionally compiles it.
5912      * @param {String} html
5913      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
5914      * @return {Roo.Template} this
5915      */
5916     set : function(html, compile){
5917         this.html = html;
5918         this.compiled = false;
5919         if(compile){
5920             this.compile();
5921         }
5922         return this;
5923     },
5924     
5925     /**
5926      * True to disable format functions (defaults to false)
5927      * @type Boolean
5928      */
5929     disableFormats : false,
5930     
5931     /**
5932     * The regular expression used to match template variables 
5933     * @type RegExp
5934     * @property 
5935     */
5936     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
5937     
5938     /**
5939      * Compiles the template into an internal function, eliminating the RegEx overhead.
5940      * @return {Roo.Template} this
5941      */
5942     compile : function(){
5943         var fm = Roo.util.Format;
5944         var useF = this.disableFormats !== true;
5945         var sep = Roo.isGecko ? "+" : ",";
5946         var fn = function(m, name, format, args){
5947             if(format && useF){
5948                 args = args ? ',' + args : "";
5949                 if(format.substr(0, 5) != "this."){
5950                     format = "fm." + format + '(';
5951                 }else{
5952                     format = 'this.call("'+ format.substr(5) + '", ';
5953                     args = ", values";
5954                 }
5955             }else{
5956                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
5957             }
5958             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
5959         };
5960         var body;
5961         // branched to use + in gecko and [].join() in others
5962         if(Roo.isGecko){
5963             body = "this.compiled = function(values){ return '" +
5964                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
5965                     "';};";
5966         }else{
5967             body = ["this.compiled = function(values){ return ['"];
5968             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
5969             body.push("'].join('');};");
5970             body = body.join('');
5971         }
5972         /**
5973          * eval:var:values
5974          * eval:var:fm
5975          */
5976         eval(body);
5977         return this;
5978     },
5979     
5980     // private function used to call members
5981     call : function(fnName, value, allValues){
5982         return this[fnName](value, allValues);
5983     },
5984     
5985     /**
5986      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
5987      * @param {String/HTMLElement/Roo.Element} el The context element
5988      * @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'})
5989      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
5990      * @return {HTMLElement/Roo.Element} The new node or Element
5991      */
5992     insertFirst: function(el, values, returnElement){
5993         return this.doInsert('afterBegin', el, values, returnElement);
5994     },
5995
5996     /**
5997      * Applies the supplied values to the template and inserts the new node(s) before el.
5998      * @param {String/HTMLElement/Roo.Element} el The context element
5999      * @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'})
6000      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
6001      * @return {HTMLElement/Roo.Element} The new node or Element
6002      */
6003     insertBefore: function(el, values, returnElement){
6004         return this.doInsert('beforeBegin', el, values, returnElement);
6005     },
6006
6007     /**
6008      * Applies the supplied values to the template and inserts the new node(s) after el.
6009      * @param {String/HTMLElement/Roo.Element} el The context element
6010      * @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'})
6011      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
6012      * @return {HTMLElement/Roo.Element} The new node or Element
6013      */
6014     insertAfter : function(el, values, returnElement){
6015         return this.doInsert('afterEnd', el, values, returnElement);
6016     },
6017     
6018     /**
6019      * Applies the supplied values to the template and appends the new node(s) to el.
6020      * @param {String/HTMLElement/Roo.Element} el The context element
6021      * @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'})
6022      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
6023      * @return {HTMLElement/Roo.Element} The new node or Element
6024      */
6025     append : function(el, values, returnElement){
6026         return this.doInsert('beforeEnd', el, values, returnElement);
6027     },
6028
6029     doInsert : function(where, el, values, returnEl){
6030         el = Roo.getDom(el);
6031         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
6032         return returnEl ? Roo.get(newNode, true) : newNode;
6033     },
6034
6035     /**
6036      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
6037      * @param {String/HTMLElement/Roo.Element} el The context element
6038      * @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'})
6039      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
6040      * @return {HTMLElement/Roo.Element} The new node or Element
6041      */
6042     overwrite : function(el, values, returnElement){
6043         el = Roo.getDom(el);
6044         el.innerHTML = this.applyTemplate(values);
6045         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
6046     }
6047 };
6048 /**
6049  * Alias for {@link #applyTemplate}
6050  * @method
6051  */
6052 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
6053
6054 // backwards compat
6055 Roo.DomHelper.Template = Roo.Template;
6056
6057 /**
6058  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
6059  * @param {String/HTMLElement} el A DOM element or its id
6060  * @returns {Roo.Template} The created template
6061  * @static
6062  */
6063 Roo.Template.from = function(el){
6064     el = Roo.getDom(el);
6065     return new Roo.Template(el.value || el.innerHTML);
6066 };/*
6067  * Based on:
6068  * Ext JS Library 1.1.1
6069  * Copyright(c) 2006-2007, Ext JS, LLC.
6070  *
6071  * Originally Released Under LGPL - original licence link has changed is not relivant.
6072  *
6073  * Fork - LGPL
6074  * <script type="text/javascript">
6075  */
6076  
6077
6078 /*
6079  * This is code is also distributed under MIT license for use
6080  * with jQuery and prototype JavaScript libraries.
6081  */
6082 /**
6083  * @class Roo.DomQuery
6084 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).
6085 <p>
6086 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>
6087
6088 <p>
6089 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.
6090 </p>
6091 <h4>Element Selectors:</h4>
6092 <ul class="list">
6093     <li> <b>*</b> any element</li>
6094     <li> <b>E</b> an element with the tag E</li>
6095     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
6096     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
6097     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
6098     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
6099 </ul>
6100 <h4>Attribute Selectors:</h4>
6101 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
6102 <ul class="list">
6103     <li> <b>E[foo]</b> has an attribute "foo"</li>
6104     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
6105     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
6106     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
6107     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
6108     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
6109     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
6110 </ul>
6111 <h4>Pseudo Classes:</h4>
6112 <ul class="list">
6113     <li> <b>E:first-child</b> E is the first child of its parent</li>
6114     <li> <b>E:last-child</b> E is the last child of its parent</li>
6115     <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>
6116     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
6117     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
6118     <li> <b>E:only-child</b> E is the only child of its parent</li>
6119     <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>
6120     <li> <b>E:first</b> the first E in the resultset</li>
6121     <li> <b>E:last</b> the last E in the resultset</li>
6122     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
6123     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
6124     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
6125     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
6126     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
6127     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
6128     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
6129     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
6130     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
6131 </ul>
6132 <h4>CSS Value Selectors:</h4>
6133 <ul class="list">
6134     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
6135     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
6136     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
6137     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
6138     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
6139     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
6140 </ul>
6141  * @static
6142  */
6143 Roo.DomQuery = function(){
6144     var cache = {}, simpleCache = {}, valueCache = {};
6145     var nonSpace = /\S/;
6146     var trimRe = /^\s+|\s+$/g;
6147     var tplRe = /\{(\d+)\}/g;
6148     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
6149     var tagTokenRe = /^(#)?([\w-\*]+)/;
6150     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
6151
6152     function child(p, index){
6153         var i = 0;
6154         var n = p.firstChild;
6155         while(n){
6156             if(n.nodeType == 1){
6157                if(++i == index){
6158                    return n;
6159                }
6160             }
6161             n = n.nextSibling;
6162         }
6163         return null;
6164     };
6165
6166     function next(n){
6167         while((n = n.nextSibling) && n.nodeType != 1);
6168         return n;
6169     };
6170
6171     function prev(n){
6172         while((n = n.previousSibling) && n.nodeType != 1);
6173         return n;
6174     };
6175
6176     function children(d){
6177         var n = d.firstChild, ni = -1;
6178             while(n){
6179                 var nx = n.nextSibling;
6180                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
6181                     d.removeChild(n);
6182                 }else{
6183                     n.nodeIndex = ++ni;
6184                 }
6185                 n = nx;
6186             }
6187             return this;
6188         };
6189
6190     function byClassName(c, a, v){
6191         if(!v){
6192             return c;
6193         }
6194         var r = [], ri = -1, cn;
6195         for(var i = 0, ci; ci = c[i]; i++){
6196             
6197             
6198             if((' '+
6199                 ( (ci instanceof SVGElement) ? ci.className.baseVal : ci.className)
6200                  +' ').indexOf(v) != -1){
6201                 r[++ri] = ci;
6202             }
6203         }
6204         return r;
6205     };
6206
6207     function attrValue(n, attr){
6208         if(!n.tagName && typeof n.length != "undefined"){
6209             n = n[0];
6210         }
6211         if(!n){
6212             return null;
6213         }
6214         if(attr == "for"){
6215             return n.htmlFor;
6216         }
6217         if(attr == "class" || attr == "className"){
6218             return (n instanceof SVGElement) ? n.className.baseVal : n.className;
6219         }
6220         return n.getAttribute(attr) || n[attr];
6221
6222     };
6223
6224     function getNodes(ns, mode, tagName){
6225         var result = [], ri = -1, cs;
6226         if(!ns){
6227             return result;
6228         }
6229         tagName = tagName || "*";
6230         if(typeof ns.getElementsByTagName != "undefined"){
6231             ns = [ns];
6232         }
6233         if(!mode){
6234             for(var i = 0, ni; ni = ns[i]; i++){
6235                 cs = ni.getElementsByTagName(tagName);
6236                 for(var j = 0, ci; ci = cs[j]; j++){
6237                     result[++ri] = ci;
6238                 }
6239             }
6240         }else if(mode == "/" || mode == ">"){
6241             var utag = tagName.toUpperCase();
6242             for(var i = 0, ni, cn; ni = ns[i]; i++){
6243                 cn = ni.children || ni.childNodes;
6244                 for(var j = 0, cj; cj = cn[j]; j++){
6245                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
6246                         result[++ri] = cj;
6247                     }
6248                 }
6249             }
6250         }else if(mode == "+"){
6251             var utag = tagName.toUpperCase();
6252             for(var i = 0, n; n = ns[i]; i++){
6253                 while((n = n.nextSibling) && n.nodeType != 1);
6254                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
6255                     result[++ri] = n;
6256                 }
6257             }
6258         }else if(mode == "~"){
6259             for(var i = 0, n; n = ns[i]; i++){
6260                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
6261                 if(n){
6262                     result[++ri] = n;
6263                 }
6264             }
6265         }
6266         return result;
6267     };
6268
6269     function concat(a, b){
6270         if(b.slice){
6271             return a.concat(b);
6272         }
6273         for(var i = 0, l = b.length; i < l; i++){
6274             a[a.length] = b[i];
6275         }
6276         return a;
6277     }
6278
6279     function byTag(cs, tagName){
6280         if(cs.tagName || cs == document){
6281             cs = [cs];
6282         }
6283         if(!tagName){
6284             return cs;
6285         }
6286         var r = [], ri = -1;
6287         tagName = tagName.toLowerCase();
6288         for(var i = 0, ci; ci = cs[i]; i++){
6289             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
6290                 r[++ri] = ci;
6291             }
6292         }
6293         return r;
6294     };
6295
6296     function byId(cs, attr, id){
6297         if(cs.tagName || cs == document){
6298             cs = [cs];
6299         }
6300         if(!id){
6301             return cs;
6302         }
6303         var r = [], ri = -1;
6304         for(var i = 0,ci; ci = cs[i]; i++){
6305             if(ci && ci.id == id){
6306                 r[++ri] = ci;
6307                 return r;
6308             }
6309         }
6310         return r;
6311     };
6312
6313     function byAttribute(cs, attr, value, op, custom){
6314         var r = [], ri = -1, st = custom=="{";
6315         var f = Roo.DomQuery.operators[op];
6316         for(var i = 0, ci; ci = cs[i]; i++){
6317             var a;
6318             if(st){
6319                 a = Roo.DomQuery.getStyle(ci, attr);
6320             }
6321             else if(attr == "class" || attr == "className"){
6322                 a = (ci instanceof SVGElement) ? ci.className.baseVal : ci.className;
6323             }else if(attr == "for"){
6324                 a = ci.htmlFor;
6325             }else if(attr == "href"){
6326                 a = ci.getAttribute("href", 2);
6327             }else{
6328                 a = ci.getAttribute(attr);
6329             }
6330             if((f && f(a, value)) || (!f && a)){
6331                 r[++ri] = ci;
6332             }
6333         }
6334         return r;
6335     };
6336
6337     function byPseudo(cs, name, value){
6338         return Roo.DomQuery.pseudos[name](cs, value);
6339     };
6340
6341     // This is for IE MSXML which does not support expandos.
6342     // IE runs the same speed using setAttribute, however FF slows way down
6343     // and Safari completely fails so they need to continue to use expandos.
6344     var isIE = window.ActiveXObject ? true : false;
6345
6346     // this eval is stop the compressor from
6347     // renaming the variable to something shorter
6348     
6349     /** eval:var:batch */
6350     var batch = 30803; 
6351
6352     var key = 30803;
6353
6354     function nodupIEXml(cs){
6355         var d = ++key;
6356         cs[0].setAttribute("_nodup", d);
6357         var r = [cs[0]];
6358         for(var i = 1, len = cs.length; i < len; i++){
6359             var c = cs[i];
6360             if(!c.getAttribute("_nodup") != d){
6361                 c.setAttribute("_nodup", d);
6362                 r[r.length] = c;
6363             }
6364         }
6365         for(var i = 0, len = cs.length; i < len; i++){
6366             cs[i].removeAttribute("_nodup");
6367         }
6368         return r;
6369     }
6370
6371     function nodup(cs){
6372         if(!cs){
6373             return [];
6374         }
6375         var len = cs.length, c, i, r = cs, cj, ri = -1;
6376         if(!len || typeof cs.nodeType != "undefined" || len == 1){
6377             return cs;
6378         }
6379         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
6380             return nodupIEXml(cs);
6381         }
6382         var d = ++key;
6383         cs[0]._nodup = d;
6384         for(i = 1; c = cs[i]; i++){
6385             if(c._nodup != d){
6386                 c._nodup = d;
6387             }else{
6388                 r = [];
6389                 for(var j = 0; j < i; j++){
6390                     r[++ri] = cs[j];
6391                 }
6392                 for(j = i+1; cj = cs[j]; j++){
6393                     if(cj._nodup != d){
6394                         cj._nodup = d;
6395                         r[++ri] = cj;
6396                     }
6397                 }
6398                 return r;
6399             }
6400         }
6401         return r;
6402     }
6403
6404     function quickDiffIEXml(c1, c2){
6405         var d = ++key;
6406         for(var i = 0, len = c1.length; i < len; i++){
6407             c1[i].setAttribute("_qdiff", d);
6408         }
6409         var r = [];
6410         for(var i = 0, len = c2.length; i < len; i++){
6411             if(c2[i].getAttribute("_qdiff") != d){
6412                 r[r.length] = c2[i];
6413             }
6414         }
6415         for(var i = 0, len = c1.length; i < len; i++){
6416            c1[i].removeAttribute("_qdiff");
6417         }
6418         return r;
6419     }
6420
6421     function quickDiff(c1, c2){
6422         var len1 = c1.length;
6423         if(!len1){
6424             return c2;
6425         }
6426         if(isIE && c1[0].selectSingleNode){
6427             return quickDiffIEXml(c1, c2);
6428         }
6429         var d = ++key;
6430         for(var i = 0; i < len1; i++){
6431             c1[i]._qdiff = d;
6432         }
6433         var r = [];
6434         for(var i = 0, len = c2.length; i < len; i++){
6435             if(c2[i]._qdiff != d){
6436                 r[r.length] = c2[i];
6437             }
6438         }
6439         return r;
6440     }
6441
6442     function quickId(ns, mode, root, id){
6443         if(ns == root){
6444            var d = root.ownerDocument || root;
6445            return d.getElementById(id);
6446         }
6447         ns = getNodes(ns, mode, "*");
6448         return byId(ns, null, id);
6449     }
6450
6451     return {
6452         getStyle : function(el, name){
6453             return Roo.fly(el).getStyle(name);
6454         },
6455         /**
6456          * Compiles a selector/xpath query into a reusable function. The returned function
6457          * takes one parameter "root" (optional), which is the context node from where the query should start.
6458          * @param {String} selector The selector/xpath query
6459          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
6460          * @return {Function}
6461          */
6462         compile : function(path, type){
6463             type = type || "select";
6464             
6465             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
6466             var q = path, mode, lq;
6467             var tk = Roo.DomQuery.matchers;
6468             var tklen = tk.length;
6469             var mm;
6470
6471             // accept leading mode switch
6472             var lmode = q.match(modeRe);
6473             if(lmode && lmode[1]){
6474                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
6475                 q = q.replace(lmode[1], "");
6476             }
6477             // strip leading slashes
6478             while(path.substr(0, 1)=="/"){
6479                 path = path.substr(1);
6480             }
6481
6482             while(q && lq != q){
6483                 lq = q;
6484                 var tm = q.match(tagTokenRe);
6485                 if(type == "select"){
6486                     if(tm){
6487                         if(tm[1] == "#"){
6488                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
6489                         }else{
6490                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
6491                         }
6492                         q = q.replace(tm[0], "");
6493                     }else if(q.substr(0, 1) != '@'){
6494                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
6495                     }
6496                 }else{
6497                     if(tm){
6498                         if(tm[1] == "#"){
6499                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
6500                         }else{
6501                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
6502                         }
6503                         q = q.replace(tm[0], "");
6504                     }
6505                 }
6506                 while(!(mm = q.match(modeRe))){
6507                     var matched = false;
6508                     for(var j = 0; j < tklen; j++){
6509                         var t = tk[j];
6510                         var m = q.match(t.re);
6511                         if(m){
6512                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
6513                                                     return m[i];
6514                                                 });
6515                             q = q.replace(m[0], "");
6516                             matched = true;
6517                             break;
6518                         }
6519                     }
6520                     // prevent infinite loop on bad selector
6521                     if(!matched){
6522                         throw 'Error parsing selector, parsing failed at "' + q + '"';
6523                     }
6524                 }
6525                 if(mm[1]){
6526                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
6527                     q = q.replace(mm[1], "");
6528                 }
6529             }
6530             fn[fn.length] = "return nodup(n);\n}";
6531             
6532              /** 
6533               * list of variables that need from compression as they are used by eval.
6534              *  eval:var:batch 
6535              *  eval:var:nodup
6536              *  eval:var:byTag
6537              *  eval:var:ById
6538              *  eval:var:getNodes
6539              *  eval:var:quickId
6540              *  eval:var:mode
6541              *  eval:var:root
6542              *  eval:var:n
6543              *  eval:var:byClassName
6544              *  eval:var:byPseudo
6545              *  eval:var:byAttribute
6546              *  eval:var:attrValue
6547              * 
6548              **/ 
6549             eval(fn.join(""));
6550             return f;
6551         },
6552
6553         /**
6554          * Selects a group of elements.
6555          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
6556          * @param {Node} root (optional) The start of the query (defaults to document).
6557          * @return {Array}
6558          */
6559         select : function(path, root, type){
6560             if(!root || root == document){
6561                 root = document;
6562             }
6563             if(typeof root == "string"){
6564                 root = document.getElementById(root);
6565             }
6566             var paths = path.split(",");
6567             var results = [];
6568             for(var i = 0, len = paths.length; i < len; i++){
6569                 var p = paths[i].replace(trimRe, "");
6570                 if(!cache[p]){
6571                     cache[p] = Roo.DomQuery.compile(p);
6572                     if(!cache[p]){
6573                         throw p + " is not a valid selector";
6574                     }
6575                 }
6576                 var result = cache[p](root);
6577                 if(result && result != document){
6578                     results = results.concat(result);
6579                 }
6580             }
6581             if(paths.length > 1){
6582                 return nodup(results);
6583             }
6584             return results;
6585         },
6586
6587         /**
6588          * Selects a single element.
6589          * @param {String} selector The selector/xpath query
6590          * @param {Node} root (optional) The start of the query (defaults to document).
6591          * @return {Element}
6592          */
6593         selectNode : function(path, root){
6594             return Roo.DomQuery.select(path, root)[0];
6595         },
6596
6597         /**
6598          * Selects the value of a node, optionally replacing null with the defaultValue.
6599          * @param {String} selector The selector/xpath query
6600          * @param {Node} root (optional) The start of the query (defaults to document).
6601          * @param {String} defaultValue
6602          */
6603         selectValue : function(path, root, defaultValue){
6604             path = path.replace(trimRe, "");
6605             if(!valueCache[path]){
6606                 valueCache[path] = Roo.DomQuery.compile(path, "select");
6607             }
6608             var n = valueCache[path](root);
6609             n = n[0] ? n[0] : n;
6610             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
6611             return ((v === null||v === undefined||v==='') ? defaultValue : v);
6612         },
6613
6614         /**
6615          * Selects the value of a node, parsing integers and floats.
6616          * @param {String} selector The selector/xpath query
6617          * @param {Node} root (optional) The start of the query (defaults to document).
6618          * @param {Number} defaultValue
6619          * @return {Number}
6620          */
6621         selectNumber : function(path, root, defaultValue){
6622             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
6623             return parseFloat(v);
6624         },
6625
6626         /**
6627          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
6628          * @param {String/HTMLElement/Array} el An element id, element or array of elements
6629          * @param {String} selector The simple selector to test
6630          * @return {Boolean}
6631          */
6632         is : function(el, ss){
6633             if(typeof el == "string"){
6634                 el = document.getElementById(el);
6635             }
6636             var isArray = (el instanceof Array);
6637             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
6638             return isArray ? (result.length == el.length) : (result.length > 0);
6639         },
6640
6641         /**
6642          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
6643          * @param {Array} el An array of elements to filter
6644          * @param {String} selector The simple selector to test
6645          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
6646          * the selector instead of the ones that match
6647          * @return {Array}
6648          */
6649         filter : function(els, ss, nonMatches){
6650             ss = ss.replace(trimRe, "");
6651             if(!simpleCache[ss]){
6652                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
6653             }
6654             var result = simpleCache[ss](els);
6655             return nonMatches ? quickDiff(result, els) : result;
6656         },
6657
6658         /**
6659          * Collection of matching regular expressions and code snippets.
6660          */
6661         matchers : [{
6662                 re: /^\.([\w-]+)/,
6663                 select: 'n = byClassName(n, null, " {1} ");'
6664             }, {
6665                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
6666                 select: 'n = byPseudo(n, "{1}", "{2}");'
6667             },{
6668                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
6669                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
6670             }, {
6671                 re: /^#([\w-]+)/,
6672                 select: 'n = byId(n, null, "{1}");'
6673             },{
6674                 re: /^@([\w-]+)/,
6675                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
6676             }
6677         ],
6678
6679         /**
6680          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
6681          * 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;.
6682          */
6683         operators : {
6684             "=" : function(a, v){
6685                 return a == v;
6686             },
6687             "!=" : function(a, v){
6688                 return a != v;
6689             },
6690             "^=" : function(a, v){
6691                 return a && a.substr(0, v.length) == v;
6692             },
6693             "$=" : function(a, v){
6694                 return a && a.substr(a.length-v.length) == v;
6695             },
6696             "*=" : function(a, v){
6697                 return a && a.indexOf(v) !== -1;
6698             },
6699             "%=" : function(a, v){
6700                 return (a % v) == 0;
6701             },
6702             "|=" : function(a, v){
6703                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
6704             },
6705             "~=" : function(a, v){
6706                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
6707             }
6708         },
6709
6710         /**
6711          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
6712          * and the argument (if any) supplied in the selector.
6713          */
6714         pseudos : {
6715             "first-child" : function(c){
6716                 var r = [], ri = -1, n;
6717                 for(var i = 0, ci; ci = n = c[i]; i++){
6718                     while((n = n.previousSibling) && n.nodeType != 1);
6719                     if(!n){
6720                         r[++ri] = ci;
6721                     }
6722                 }
6723                 return r;
6724             },
6725
6726             "last-child" : function(c){
6727                 var r = [], ri = -1, n;
6728                 for(var i = 0, ci; ci = n = c[i]; i++){
6729                     while((n = n.nextSibling) && n.nodeType != 1);
6730                     if(!n){
6731                         r[++ri] = ci;
6732                     }
6733                 }
6734                 return r;
6735             },
6736
6737             "nth-child" : function(c, a) {
6738                 var r = [], ri = -1;
6739                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
6740                 var f = (m[1] || 1) - 0, l = m[2] - 0;
6741                 for(var i = 0, n; n = c[i]; i++){
6742                     var pn = n.parentNode;
6743                     if (batch != pn._batch) {
6744                         var j = 0;
6745                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
6746                             if(cn.nodeType == 1){
6747                                cn.nodeIndex = ++j;
6748                             }
6749                         }
6750                         pn._batch = batch;
6751                     }
6752                     if (f == 1) {
6753                         if (l == 0 || n.nodeIndex == l){
6754                             r[++ri] = n;
6755                         }
6756                     } else if ((n.nodeIndex + l) % f == 0){
6757                         r[++ri] = n;
6758                     }
6759                 }
6760
6761                 return r;
6762             },
6763
6764             "only-child" : function(c){
6765                 var r = [], ri = -1;;
6766                 for(var i = 0, ci; ci = c[i]; i++){
6767                     if(!prev(ci) && !next(ci)){
6768                         r[++ri] = ci;
6769                     }
6770                 }
6771                 return r;
6772             },
6773
6774             "empty" : function(c){
6775                 var r = [], ri = -1;
6776                 for(var i = 0, ci; ci = c[i]; i++){
6777                     var cns = ci.childNodes, j = 0, cn, empty = true;
6778                     while(cn = cns[j]){
6779                         ++j;
6780                         if(cn.nodeType == 1 || cn.nodeType == 3){
6781                             empty = false;
6782                             break;
6783                         }
6784                     }
6785                     if(empty){
6786                         r[++ri] = ci;
6787                     }
6788                 }
6789                 return r;
6790             },
6791
6792             "contains" : function(c, v){
6793                 var r = [], ri = -1;
6794                 for(var i = 0, ci; ci = c[i]; i++){
6795                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
6796                         r[++ri] = ci;
6797                     }
6798                 }
6799                 return r;
6800             },
6801
6802             "nodeValue" : function(c, v){
6803                 var r = [], ri = -1;
6804                 for(var i = 0, ci; ci = c[i]; i++){
6805                     if(ci.firstChild && ci.firstChild.nodeValue == v){
6806                         r[++ri] = ci;
6807                     }
6808                 }
6809                 return r;
6810             },
6811
6812             "checked" : function(c){
6813                 var r = [], ri = -1;
6814                 for(var i = 0, ci; ci = c[i]; i++){
6815                     if(ci.checked == true){
6816                         r[++ri] = ci;
6817                     }
6818                 }
6819                 return r;
6820             },
6821
6822             "not" : function(c, ss){
6823                 return Roo.DomQuery.filter(c, ss, true);
6824             },
6825
6826             "odd" : function(c){
6827                 return this["nth-child"](c, "odd");
6828             },
6829
6830             "even" : function(c){
6831                 return this["nth-child"](c, "even");
6832             },
6833
6834             "nth" : function(c, a){
6835                 return c[a-1] || [];
6836             },
6837
6838             "first" : function(c){
6839                 return c[0] || [];
6840             },
6841
6842             "last" : function(c){
6843                 return c[c.length-1] || [];
6844             },
6845
6846             "has" : function(c, ss){
6847                 var s = Roo.DomQuery.select;
6848                 var r = [], ri = -1;
6849                 for(var i = 0, ci; ci = c[i]; i++){
6850                     if(s(ss, ci).length > 0){
6851                         r[++ri] = ci;
6852                     }
6853                 }
6854                 return r;
6855             },
6856
6857             "next" : function(c, ss){
6858                 var is = Roo.DomQuery.is;
6859                 var r = [], ri = -1;
6860                 for(var i = 0, ci; ci = c[i]; i++){
6861                     var n = next(ci);
6862                     if(n && is(n, ss)){
6863                         r[++ri] = ci;
6864                     }
6865                 }
6866                 return r;
6867             },
6868
6869             "prev" : function(c, ss){
6870                 var is = Roo.DomQuery.is;
6871                 var r = [], ri = -1;
6872                 for(var i = 0, ci; ci = c[i]; i++){
6873                     var n = prev(ci);
6874                     if(n && is(n, ss)){
6875                         r[++ri] = ci;
6876                     }
6877                 }
6878                 return r;
6879             }
6880         }
6881     };
6882 }();
6883
6884 /**
6885  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
6886  * @param {String} path The selector/xpath query
6887  * @param {Node} root (optional) The start of the query (defaults to document).
6888  * @return {Array}
6889  * @member Roo
6890  * @method query
6891  */
6892 Roo.query = Roo.DomQuery.select;
6893 /*
6894  * Based on:
6895  * Ext JS Library 1.1.1
6896  * Copyright(c) 2006-2007, Ext JS, LLC.
6897  *
6898  * Originally Released Under LGPL - original licence link has changed is not relivant.
6899  *
6900  * Fork - LGPL
6901  * <script type="text/javascript">
6902  */
6903
6904 /**
6905  * @class Roo.util.Observable
6906  * Base class that provides a common interface for publishing events. Subclasses are expected to
6907  * to have a property "events" with all the events defined.<br>
6908  * For example:
6909  * <pre><code>
6910  Employee = function(name){
6911     this.name = name;
6912     this.addEvents({
6913         "fired" : true,
6914         "quit" : true
6915     });
6916  }
6917  Roo.extend(Employee, Roo.util.Observable);
6918 </code></pre>
6919  * @param {Object} config properties to use (incuding events / listeners)
6920  */
6921
6922 Roo.util.Observable = function(cfg){
6923     
6924     cfg = cfg|| {};
6925     this.addEvents(cfg.events || {});
6926     if (cfg.events) {
6927         delete cfg.events; // make sure
6928     }
6929      
6930     Roo.apply(this, cfg);
6931     
6932     if(this.listeners){
6933         this.on(this.listeners);
6934         delete this.listeners;
6935     }
6936 };
6937 Roo.util.Observable.prototype = {
6938     /** 
6939  * @cfg {Object} listeners  list of events and functions to call for this object, 
6940  * For example :
6941  * <pre><code>
6942     listeners :  { 
6943        'click' : function(e) {
6944            ..... 
6945         } ,
6946         .... 
6947     } 
6948   </code></pre>
6949  */
6950     
6951     
6952     /**
6953      * Fires the specified event with the passed parameters (minus the event name).
6954      * @param {String} eventName
6955      * @param {Object...} args Variable number of parameters are passed to handlers
6956      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
6957      */
6958     fireEvent : function(){
6959         var ce = this.events[arguments[0].toLowerCase()];
6960         if(typeof ce == "object"){
6961             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
6962         }else{
6963             return true;
6964         }
6965     },
6966
6967     // private
6968     filterOptRe : /^(?:scope|delay|buffer|single)$/,
6969
6970     /**
6971      * Appends an event handler to this component
6972      * @param {String}   eventName The type of event to listen for
6973      * @param {Function} handler The method the event invokes
6974      * @param {Object}   scope (optional) The scope in which to execute the handler
6975      * function. The handler function's "this" context.
6976      * @param {Object}   options (optional) An object containing handler configuration
6977      * properties. This may contain any of the following properties:<ul>
6978      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6979      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6980      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6981      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6982      * by the specified number of milliseconds. If the event fires again within that time, the original
6983      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6984      * </ul><br>
6985      * <p>
6986      * <b>Combining Options</b><br>
6987      * Using the options argument, it is possible to combine different types of listeners:<br>
6988      * <br>
6989      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
6990                 <pre><code>
6991                 el.on('click', this.onClick, this, {
6992                         single: true,
6993                 delay: 100,
6994                 forumId: 4
6995                 });
6996                 </code></pre>
6997      * <p>
6998      * <b>Attaching multiple handlers in 1 call</b><br>
6999      * The method also allows for a single argument to be passed which is a config object containing properties
7000      * which specify multiple handlers.
7001      * <pre><code>
7002                 el.on({
7003                         'click': {
7004                         fn: this.onClick,
7005                         scope: this,
7006                         delay: 100
7007                 }, 
7008                 'mouseover': {
7009                         fn: this.onMouseOver,
7010                         scope: this
7011                 },
7012                 'mouseout': {
7013                         fn: this.onMouseOut,
7014                         scope: this
7015                 }
7016                 });
7017                 </code></pre>
7018      * <p>
7019      * Or a shorthand syntax which passes the same scope object to all handlers:
7020         <pre><code>
7021                 el.on({
7022                         'click': this.onClick,
7023                 'mouseover': this.onMouseOver,
7024                 'mouseout': this.onMouseOut,
7025                 scope: this
7026                 });
7027                 </code></pre>
7028      */
7029     addListener : function(eventName, fn, scope, o){
7030         if(typeof eventName == "object"){
7031             o = eventName;
7032             for(var e in o){
7033                 if(this.filterOptRe.test(e)){
7034                     continue;
7035                 }
7036                 if(typeof o[e] == "function"){
7037                     // shared options
7038                     this.addListener(e, o[e], o.scope,  o);
7039                 }else{
7040                     // individual options
7041                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
7042                 }
7043             }
7044             return;
7045         }
7046         o = (!o || typeof o == "boolean") ? {} : o;
7047         eventName = eventName.toLowerCase();
7048         var ce = this.events[eventName] || true;
7049         if(typeof ce == "boolean"){
7050             ce = new Roo.util.Event(this, eventName);
7051             this.events[eventName] = ce;
7052         }
7053         ce.addListener(fn, scope, o);
7054     },
7055
7056     /**
7057      * Removes a listener
7058      * @param {String}   eventName     The type of event to listen for
7059      * @param {Function} handler        The handler to remove
7060      * @param {Object}   scope  (optional) The scope (this object) for the handler
7061      */
7062     removeListener : function(eventName, fn, scope){
7063         var ce = this.events[eventName.toLowerCase()];
7064         if(typeof ce == "object"){
7065             ce.removeListener(fn, scope);
7066         }
7067     },
7068
7069     /**
7070      * Removes all listeners for this object
7071      */
7072     purgeListeners : function(){
7073         for(var evt in this.events){
7074             if(typeof this.events[evt] == "object"){
7075                  this.events[evt].clearListeners();
7076             }
7077         }
7078     },
7079
7080     relayEvents : function(o, events){
7081         var createHandler = function(ename){
7082             return function(){
7083                  
7084                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
7085             };
7086         };
7087         for(var i = 0, len = events.length; i < len; i++){
7088             var ename = events[i];
7089             if(!this.events[ename]){
7090                 this.events[ename] = true;
7091             };
7092             o.on(ename, createHandler(ename), this);
7093         }
7094     },
7095
7096     /**
7097      * Used to define events on this Observable
7098      * @param {Object} object The object with the events defined
7099      */
7100     addEvents : function(o){
7101         if(!this.events){
7102             this.events = {};
7103         }
7104         Roo.applyIf(this.events, o);
7105     },
7106
7107     /**
7108      * Checks to see if this object has any listeners for a specified event
7109      * @param {String} eventName The name of the event to check for
7110      * @return {Boolean} True if the event is being listened for, else false
7111      */
7112     hasListener : function(eventName){
7113         var e = this.events[eventName];
7114         return typeof e == "object" && e.listeners.length > 0;
7115     }
7116 };
7117 /**
7118  * Appends an event handler to this element (shorthand for addListener)
7119  * @param {String}   eventName     The type of event to listen for
7120  * @param {Function} handler        The method the event invokes
7121  * @param {Object}   scope (optional) The scope in which to execute the handler
7122  * function. The handler function's "this" context.
7123  * @param {Object}   options  (optional)
7124  * @method
7125  */
7126 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
7127 /**
7128  * Removes a listener (shorthand for removeListener)
7129  * @param {String}   eventName     The type of event to listen for
7130  * @param {Function} handler        The handler to remove
7131  * @param {Object}   scope  (optional) The scope (this object) for the handler
7132  * @method
7133  */
7134 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
7135
7136 /**
7137  * Starts capture on the specified Observable. All events will be passed
7138  * to the supplied function with the event name + standard signature of the event
7139  * <b>before</b> the event is fired. If the supplied function returns false,
7140  * the event will not fire.
7141  * @param {Observable} o The Observable to capture
7142  * @param {Function} fn The function to call
7143  * @param {Object} scope (optional) The scope (this object) for the fn
7144  * @static
7145  */
7146 Roo.util.Observable.capture = function(o, fn, scope){
7147     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
7148 };
7149
7150 /**
7151  * Removes <b>all</b> added captures from the Observable.
7152  * @param {Observable} o The Observable to release
7153  * @static
7154  */
7155 Roo.util.Observable.releaseCapture = function(o){
7156     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
7157 };
7158
7159 (function(){
7160
7161     var createBuffered = function(h, o, scope){
7162         var task = new Roo.util.DelayedTask();
7163         return function(){
7164             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
7165         };
7166     };
7167
7168     var createSingle = function(h, e, fn, scope){
7169         return function(){
7170             e.removeListener(fn, scope);
7171             return h.apply(scope, arguments);
7172         };
7173     };
7174
7175     var createDelayed = function(h, o, scope){
7176         return function(){
7177             var args = Array.prototype.slice.call(arguments, 0);
7178             setTimeout(function(){
7179                 h.apply(scope, args);
7180             }, o.delay || 10);
7181         };
7182     };
7183
7184     Roo.util.Event = function(obj, name){
7185         this.name = name;
7186         this.obj = obj;
7187         this.listeners = [];
7188     };
7189
7190     Roo.util.Event.prototype = {
7191         addListener : function(fn, scope, options){
7192             var o = options || {};
7193             scope = scope || this.obj;
7194             if(!this.isListening(fn, scope)){
7195                 var l = {fn: fn, scope: scope, options: o};
7196                 var h = fn;
7197                 if(o.delay){
7198                     h = createDelayed(h, o, scope);
7199                 }
7200                 if(o.single){
7201                     h = createSingle(h, this, fn, scope);
7202                 }
7203                 if(o.buffer){
7204                     h = createBuffered(h, o, scope);
7205                 }
7206                 l.fireFn = h;
7207                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
7208                     this.listeners.push(l);
7209                 }else{
7210                     this.listeners = this.listeners.slice(0);
7211                     this.listeners.push(l);
7212                 }
7213             }
7214         },
7215
7216         findListener : function(fn, scope){
7217             scope = scope || this.obj;
7218             var ls = this.listeners;
7219             for(var i = 0, len = ls.length; i < len; i++){
7220                 var l = ls[i];
7221                 if(l.fn == fn && l.scope == scope){
7222                     return i;
7223                 }
7224             }
7225             return -1;
7226         },
7227
7228         isListening : function(fn, scope){
7229             return this.findListener(fn, scope) != -1;
7230         },
7231
7232         removeListener : function(fn, scope){
7233             var index;
7234             if((index = this.findListener(fn, scope)) != -1){
7235                 if(!this.firing){
7236                     this.listeners.splice(index, 1);
7237                 }else{
7238                     this.listeners = this.listeners.slice(0);
7239                     this.listeners.splice(index, 1);
7240                 }
7241                 return true;
7242             }
7243             return false;
7244         },
7245
7246         clearListeners : function(){
7247             this.listeners = [];
7248         },
7249
7250         fire : function(){
7251             var ls = this.listeners, scope, len = ls.length;
7252             if(len > 0){
7253                 this.firing = true;
7254                 var args = Array.prototype.slice.call(arguments, 0);                
7255                 for(var i = 0; i < len; i++){
7256                     var l = ls[i];
7257                     if(l.fireFn.apply(l.scope||this.obj||window, args) === false){
7258                         this.firing = false;
7259                         return false;
7260                     }
7261                 }
7262                 this.firing = false;
7263             }
7264             return true;
7265         }
7266     };
7267 })();/*
7268  * RooJS Library 
7269  * Copyright(c) 2007-2017, Roo J Solutions Ltd
7270  *
7271  * Licence LGPL 
7272  *
7273  */
7274  
7275 /**
7276  * @class Roo.Document
7277  * @extends Roo.util.Observable
7278  * This is a convience class to wrap up the main document loading code.. , rather than adding Roo.onReady(......)
7279  * 
7280  * @param {Object} config the methods and properties of the 'base' class for the application.
7281  * 
7282  *  Generic Page handler - implement this to start your app..
7283  * 
7284  * eg.
7285  *  MyProject = new Roo.Document({
7286         events : {
7287             'load' : true // your events..
7288         },
7289         listeners : {
7290             'ready' : function() {
7291                 // fired on Roo.onReady()
7292             }
7293         }
7294  * 
7295  */
7296 Roo.Document = function(cfg) {
7297      
7298     this.addEvents({ 
7299         'ready' : true
7300     });
7301     Roo.util.Observable.call(this,cfg);
7302     
7303     var _this = this;
7304     
7305     Roo.onReady(function() {
7306         _this.fireEvent('ready');
7307     },null,false);
7308     
7309     
7310 }
7311
7312 Roo.extend(Roo.Document, Roo.util.Observable, {});/*
7313  * Based on:
7314  * Ext JS Library 1.1.1
7315  * Copyright(c) 2006-2007, Ext JS, LLC.
7316  *
7317  * Originally Released Under LGPL - original licence link has changed is not relivant.
7318  *
7319  * Fork - LGPL
7320  * <script type="text/javascript">
7321  */
7322
7323 /**
7324  * @class Roo.EventManager
7325  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
7326  * several useful events directly.
7327  * See {@link Roo.EventObject} for more details on normalized event objects.
7328  * @static
7329  */
7330 Roo.EventManager = function(){
7331     var docReadyEvent, docReadyProcId, docReadyState = false;
7332     var resizeEvent, resizeTask, textEvent, textSize;
7333     var E = Roo.lib.Event;
7334     var D = Roo.lib.Dom;
7335
7336     
7337     
7338
7339     var fireDocReady = function(){
7340         if(!docReadyState){
7341             docReadyState = true;
7342             Roo.isReady = true;
7343             if(docReadyProcId){
7344                 clearInterval(docReadyProcId);
7345             }
7346             if(Roo.isGecko || Roo.isOpera) {
7347                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
7348             }
7349             if(Roo.isIE){
7350                 var defer = document.getElementById("ie-deferred-loader");
7351                 if(defer){
7352                     defer.onreadystatechange = null;
7353                     defer.parentNode.removeChild(defer);
7354                 }
7355             }
7356             if(docReadyEvent){
7357                 docReadyEvent.fire();
7358                 docReadyEvent.clearListeners();
7359             }
7360         }
7361     };
7362     
7363     var initDocReady = function(){
7364         docReadyEvent = new Roo.util.Event();
7365         if(Roo.isGecko || Roo.isOpera) {
7366             document.addEventListener("DOMContentLoaded", fireDocReady, false);
7367         }else if(Roo.isIE){
7368             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
7369             var defer = document.getElementById("ie-deferred-loader");
7370             defer.onreadystatechange = function(){
7371                 if(this.readyState == "complete"){
7372                     fireDocReady();
7373                 }
7374             };
7375         }else if(Roo.isSafari){ 
7376             docReadyProcId = setInterval(function(){
7377                 var rs = document.readyState;
7378                 if(rs == "complete") {
7379                     fireDocReady();     
7380                  }
7381             }, 10);
7382         }
7383         // no matter what, make sure it fires on load
7384         E.on(window, "load", fireDocReady);
7385     };
7386
7387     var createBuffered = function(h, o){
7388         var task = new Roo.util.DelayedTask(h);
7389         return function(e){
7390             // create new event object impl so new events don't wipe out properties
7391             e = new Roo.EventObjectImpl(e);
7392             task.delay(o.buffer, h, null, [e]);
7393         };
7394     };
7395
7396     var createSingle = function(h, el, ename, fn){
7397         return function(e){
7398             Roo.EventManager.removeListener(el, ename, fn);
7399             h(e);
7400         };
7401     };
7402
7403     var createDelayed = function(h, o){
7404         return function(e){
7405             // create new event object impl so new events don't wipe out properties
7406             e = new Roo.EventObjectImpl(e);
7407             setTimeout(function(){
7408                 h(e);
7409             }, o.delay || 10);
7410         };
7411     };
7412     var transitionEndVal = false;
7413     
7414     var transitionEnd = function()
7415     {
7416         if (transitionEndVal) {
7417             return transitionEndVal;
7418         }
7419         var el = document.createElement('div');
7420
7421         var transEndEventNames = {
7422             WebkitTransition : 'webkitTransitionEnd',
7423             MozTransition    : 'transitionend',
7424             OTransition      : 'oTransitionEnd otransitionend',
7425             transition       : 'transitionend'
7426         };
7427     
7428         for (var name in transEndEventNames) {
7429             if (el.style[name] !== undefined) {
7430                 transitionEndVal = transEndEventNames[name];
7431                 return  transitionEndVal ;
7432             }
7433         }
7434     }
7435     
7436   
7437
7438     var listen = function(element, ename, opt, fn, scope)
7439     {
7440         var o = (!opt || typeof opt == "boolean") ? {} : opt;
7441         fn = fn || o.fn; scope = scope || o.scope;
7442         var el = Roo.getDom(element);
7443         
7444         
7445         if(!el){
7446             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
7447         }
7448         
7449         if (ename == 'transitionend') {
7450             ename = transitionEnd();
7451         }
7452         var h = function(e){
7453             e = Roo.EventObject.setEvent(e);
7454             var t;
7455             if(o.delegate){
7456                 t = e.getTarget(o.delegate, el);
7457                 if(!t){
7458                     return;
7459                 }
7460             }else{
7461                 t = e.target;
7462             }
7463             if(o.stopEvent === true){
7464                 e.stopEvent();
7465             }
7466             if(o.preventDefault === true){
7467                e.preventDefault();
7468             }
7469             if(o.stopPropagation === true){
7470                 e.stopPropagation();
7471             }
7472
7473             if(o.normalized === false){
7474                 e = e.browserEvent;
7475             }
7476
7477             fn.call(scope || el, e, t, o);
7478         };
7479         if(o.delay){
7480             h = createDelayed(h, o);
7481         }
7482         if(o.single){
7483             h = createSingle(h, el, ename, fn);
7484         }
7485         if(o.buffer){
7486             h = createBuffered(h, o);
7487         }
7488         
7489         fn._handlers = fn._handlers || [];
7490         
7491         
7492         fn._handlers.push([Roo.id(el), ename, h]);
7493         
7494         
7495          
7496         E.on(el, ename, h); // this adds the actuall listener to the object..
7497         
7498         
7499         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
7500             el.addEventListener("DOMMouseScroll", h, false);
7501             E.on(window, 'unload', function(){
7502                 el.removeEventListener("DOMMouseScroll", h, false);
7503             });
7504         }
7505         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
7506             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
7507         }
7508         return h;
7509     };
7510
7511     var stopListening = function(el, ename, fn){
7512         var id = Roo.id(el), hds = fn._handlers, hd = fn;
7513         if(hds){
7514             for(var i = 0, len = hds.length; i < len; i++){
7515                 var h = hds[i];
7516                 if(h[0] == id && h[1] == ename){
7517                     hd = h[2];
7518                     hds.splice(i, 1);
7519                     break;
7520                 }
7521             }
7522         }
7523         E.un(el, ename, hd);
7524         el = Roo.getDom(el);
7525         if(ename == "mousewheel" && el.addEventListener){
7526             el.removeEventListener("DOMMouseScroll", hd, false);
7527         }
7528         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
7529             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
7530         }
7531     };
7532
7533     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
7534     
7535     var pub = {
7536         
7537         
7538         /** 
7539          * Fix for doc tools
7540          * @scope Roo.EventManager
7541          */
7542         
7543         
7544         /** 
7545          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
7546          * object with a Roo.EventObject
7547          * @param {Function} fn        The method the event invokes
7548          * @param {Object}   scope    An object that becomes the scope of the handler
7549          * @param {boolean}  override If true, the obj passed in becomes
7550          *                             the execution scope of the listener
7551          * @return {Function} The wrapped function
7552          * @deprecated
7553          */
7554         wrap : function(fn, scope, override){
7555             return function(e){
7556                 Roo.EventObject.setEvent(e);
7557                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
7558             };
7559         },
7560         
7561         /**
7562      * Appends an event handler to an element (shorthand for addListener)
7563      * @param {String/HTMLElement}   element        The html element or id to assign the
7564      * @param {String}   eventName The type of event to listen for
7565      * @param {Function} handler The method the event invokes
7566      * @param {Object}   scope (optional) The scope in which to execute the handler
7567      * function. The handler function's "this" context.
7568      * @param {Object}   options (optional) An object containing handler configuration
7569      * properties. This may contain any of the following properties:<ul>
7570      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
7571      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
7572      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
7573      * <li>preventDefault {Boolean} True to prevent the default action</li>
7574      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
7575      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
7576      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
7577      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
7578      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
7579      * by the specified number of milliseconds. If the event fires again within that time, the original
7580      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
7581      * </ul><br>
7582      * <p>
7583      * <b>Combining Options</b><br>
7584      * Using the options argument, it is possible to combine different types of listeners:<br>
7585      * <br>
7586      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
7587      * Code:<pre><code>
7588 el.on('click', this.onClick, this, {
7589     single: true,
7590     delay: 100,
7591     stopEvent : true,
7592     forumId: 4
7593 });</code></pre>
7594      * <p>
7595      * <b>Attaching multiple handlers in 1 call</b><br>
7596       * The method also allows for a single argument to be passed which is a config object containing properties
7597      * which specify multiple handlers.
7598      * <p>
7599      * Code:<pre><code>
7600 el.on({
7601     'click' : {
7602         fn: this.onClick
7603         scope: this,
7604         delay: 100
7605     },
7606     'mouseover' : {
7607         fn: this.onMouseOver
7608         scope: this
7609     },
7610     'mouseout' : {
7611         fn: this.onMouseOut
7612         scope: this
7613     }
7614 });</code></pre>
7615      * <p>
7616      * Or a shorthand syntax:<br>
7617      * Code:<pre><code>
7618 el.on({
7619     'click' : this.onClick,
7620     'mouseover' : this.onMouseOver,
7621     'mouseout' : this.onMouseOut
7622     scope: this
7623 });</code></pre>
7624      */
7625         addListener : function(element, eventName, fn, scope, options){
7626             if(typeof eventName == "object"){
7627                 var o = eventName;
7628                 for(var e in o){
7629                     if(propRe.test(e)){
7630                         continue;
7631                     }
7632                     if(typeof o[e] == "function"){
7633                         // shared options
7634                         listen(element, e, o, o[e], o.scope);
7635                     }else{
7636                         // individual options
7637                         listen(element, e, o[e]);
7638                     }
7639                 }
7640                 return;
7641             }
7642             return listen(element, eventName, options, fn, scope);
7643         },
7644         
7645         /**
7646          * Removes an event handler
7647          *
7648          * @param {String/HTMLElement}   element        The id or html element to remove the 
7649          *                             event from
7650          * @param {String}   eventName     The type of event
7651          * @param {Function} fn
7652          * @return {Boolean} True if a listener was actually removed
7653          */
7654         removeListener : function(element, eventName, fn){
7655             return stopListening(element, eventName, fn);
7656         },
7657         
7658         /**
7659          * Fires when the document is ready (before onload and before images are loaded). Can be 
7660          * accessed shorthanded Roo.onReady().
7661          * @param {Function} fn        The method the event invokes
7662          * @param {Object}   scope    An  object that becomes the scope of the handler
7663          * @param {boolean}  options
7664          */
7665         onDocumentReady : function(fn, scope, options){
7666             if(docReadyState){ // if it already fired
7667                 docReadyEvent.addListener(fn, scope, options);
7668                 docReadyEvent.fire();
7669                 docReadyEvent.clearListeners();
7670                 return;
7671             }
7672             if(!docReadyEvent){
7673                 initDocReady();
7674             }
7675             docReadyEvent.addListener(fn, scope, options);
7676         },
7677         
7678         /**
7679          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
7680          * @param {Function} fn        The method the event invokes
7681          * @param {Object}   scope    An object that becomes the scope of the handler
7682          * @param {boolean}  options
7683          */
7684         onWindowResize : function(fn, scope, options)
7685         {
7686             if(!resizeEvent){
7687                 resizeEvent = new Roo.util.Event();
7688                 resizeTask = new Roo.util.DelayedTask(function(){
7689                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
7690                 });
7691                 E.on(window, "resize", function()
7692                 {
7693                     if (Roo.isIE) {
7694                         resizeTask.delay(50);
7695                     } else {
7696                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
7697                     }
7698                 });
7699             }
7700             resizeEvent.addListener(fn, scope, options);
7701         },
7702
7703         /**
7704          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
7705          * @param {Function} fn        The method the event invokes
7706          * @param {Object}   scope    An object that becomes the scope of the handler
7707          * @param {boolean}  options
7708          */
7709         onTextResize : function(fn, scope, options){
7710             if(!textEvent){
7711                 textEvent = new Roo.util.Event();
7712                 var textEl = new Roo.Element(document.createElement('div'));
7713                 textEl.dom.className = 'x-text-resize';
7714                 textEl.dom.innerHTML = 'X';
7715                 textEl.appendTo(document.body);
7716                 textSize = textEl.dom.offsetHeight;
7717                 setInterval(function(){
7718                     if(textEl.dom.offsetHeight != textSize){
7719                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
7720                     }
7721                 }, this.textResizeInterval);
7722             }
7723             textEvent.addListener(fn, scope, options);
7724         },
7725
7726         /**
7727          * Removes the passed window resize listener.
7728          * @param {Function} fn        The method the event invokes
7729          * @param {Object}   scope    The scope of handler
7730          */
7731         removeResizeListener : function(fn, scope){
7732             if(resizeEvent){
7733                 resizeEvent.removeListener(fn, scope);
7734             }
7735         },
7736
7737         // private
7738         fireResize : function(){
7739             if(resizeEvent){
7740                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
7741             }   
7742         },
7743         /**
7744          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
7745          */
7746         ieDeferSrc : false,
7747         /**
7748          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
7749          */
7750         textResizeInterval : 50
7751     };
7752     
7753     /**
7754      * Fix for doc tools
7755      * @scopeAlias pub=Roo.EventManager
7756      */
7757     
7758      /**
7759      * Appends an event handler to an element (shorthand for addListener)
7760      * @param {String/HTMLElement}   element        The html element or id to assign the
7761      * @param {String}   eventName The type of event to listen for
7762      * @param {Function} handler The method the event invokes
7763      * @param {Object}   scope (optional) The scope in which to execute the handler
7764      * function. The handler function's "this" context.
7765      * @param {Object}   options (optional) An object containing handler configuration
7766      * properties. This may contain any of the following properties:<ul>
7767      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
7768      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
7769      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
7770      * <li>preventDefault {Boolean} True to prevent the default action</li>
7771      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
7772      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
7773      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
7774      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
7775      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
7776      * by the specified number of milliseconds. If the event fires again within that time, the original
7777      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
7778      * </ul><br>
7779      * <p>
7780      * <b>Combining Options</b><br>
7781      * Using the options argument, it is possible to combine different types of listeners:<br>
7782      * <br>
7783      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
7784      * Code:<pre><code>
7785 el.on('click', this.onClick, this, {
7786     single: true,
7787     delay: 100,
7788     stopEvent : true,
7789     forumId: 4
7790 });</code></pre>
7791      * <p>
7792      * <b>Attaching multiple handlers in 1 call</b><br>
7793       * The method also allows for a single argument to be passed which is a config object containing properties
7794      * which specify multiple handlers.
7795      * <p>
7796      * Code:<pre><code>
7797 el.on({
7798     'click' : {
7799         fn: this.onClick
7800         scope: this,
7801         delay: 100
7802     },
7803     'mouseover' : {
7804         fn: this.onMouseOver
7805         scope: this
7806     },
7807     'mouseout' : {
7808         fn: this.onMouseOut
7809         scope: this
7810     }
7811 });</code></pre>
7812      * <p>
7813      * Or a shorthand syntax:<br>
7814      * Code:<pre><code>
7815 el.on({
7816     'click' : this.onClick,
7817     'mouseover' : this.onMouseOver,
7818     'mouseout' : this.onMouseOut
7819     scope: this
7820 });</code></pre>
7821      */
7822     pub.on = pub.addListener;
7823     pub.un = pub.removeListener;
7824
7825     pub.stoppedMouseDownEvent = new Roo.util.Event();
7826     return pub;
7827 }();
7828 /**
7829   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
7830   * @param {Function} fn        The method the event invokes
7831   * @param {Object}   scope    An  object that becomes the scope of the handler
7832   * @param {boolean}  override If true, the obj passed in becomes
7833   *                             the execution scope of the listener
7834   * @member Roo
7835   * @method onReady
7836  */
7837 Roo.onReady = Roo.EventManager.onDocumentReady;
7838
7839 Roo.onReady(function(){
7840     var bd = Roo.get(document.body);
7841     if(!bd){ return; }
7842
7843     var cls = [
7844             Roo.isIE ? "roo-ie"
7845             : Roo.isIE11 ? "roo-ie11"
7846             : Roo.isEdge ? "roo-edge"
7847             : Roo.isGecko ? "roo-gecko"
7848             : Roo.isOpera ? "roo-opera"
7849             : Roo.isSafari ? "roo-safari" : ""];
7850
7851     if(Roo.isMac){
7852         cls.push("roo-mac");
7853     }
7854     if(Roo.isLinux){
7855         cls.push("roo-linux");
7856     }
7857     if(Roo.isIOS){
7858         cls.push("roo-ios");
7859     }
7860     if(Roo.isTouch){
7861         cls.push("roo-touch");
7862     }
7863     if(Roo.isBorderBox){
7864         cls.push('roo-border-box');
7865     }
7866     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
7867         var p = bd.dom.parentNode;
7868         if(p){
7869             p.className += ' roo-strict';
7870         }
7871     }
7872     bd.addClass(cls.join(' '));
7873 });
7874
7875 /**
7876  * @class Roo.EventObject
7877  * EventObject exposes the Yahoo! UI Event functionality directly on the object
7878  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
7879  * Example:
7880  * <pre><code>
7881  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
7882     e.preventDefault();
7883     var target = e.getTarget();
7884     ...
7885  }
7886  var myDiv = Roo.get("myDiv");
7887  myDiv.on("click", handleClick);
7888  //or
7889  Roo.EventManager.on("myDiv", 'click', handleClick);
7890  Roo.EventManager.addListener("myDiv", 'click', handleClick);
7891  </code></pre>
7892  * @static
7893  */
7894 Roo.EventObject = function(){
7895     
7896     var E = Roo.lib.Event;
7897     
7898     // safari keypress events for special keys return bad keycodes
7899     var safariKeys = {
7900         63234 : 37, // left
7901         63235 : 39, // right
7902         63232 : 38, // up
7903         63233 : 40, // down
7904         63276 : 33, // page up
7905         63277 : 34, // page down
7906         63272 : 46, // delete
7907         63273 : 36, // home
7908         63275 : 35  // end
7909     };
7910
7911     // normalize button clicks
7912     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
7913                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
7914
7915     Roo.EventObjectImpl = function(e){
7916         if(e){
7917             this.setEvent(e.browserEvent || e);
7918         }
7919     };
7920     Roo.EventObjectImpl.prototype = {
7921         /**
7922          * Used to fix doc tools.
7923          * @scope Roo.EventObject.prototype
7924          */
7925             
7926
7927         
7928         
7929         /** The normal browser event */
7930         browserEvent : null,
7931         /** The button pressed in a mouse event */
7932         button : -1,
7933         /** True if the shift key was down during the event */
7934         shiftKey : false,
7935         /** True if the control key was down during the event */
7936         ctrlKey : false,
7937         /** True if the alt key was down during the event */
7938         altKey : false,
7939
7940         /** Key constant 
7941         * @type Number */
7942         BACKSPACE : 8,
7943         /** Key constant 
7944         * @type Number */
7945         TAB : 9,
7946         /** Key constant 
7947         * @type Number */
7948         RETURN : 13,
7949         /** Key constant 
7950         * @type Number */
7951         ENTER : 13,
7952         /** Key constant 
7953         * @type Number */
7954         SHIFT : 16,
7955         /** Key constant 
7956         * @type Number */
7957         CONTROL : 17,
7958         /** Key constant 
7959         * @type Number */
7960         ESC : 27,
7961         /** Key constant 
7962         * @type Number */
7963         SPACE : 32,
7964         /** Key constant 
7965         * @type Number */
7966         PAGEUP : 33,
7967         /** Key constant 
7968         * @type Number */
7969         PAGEDOWN : 34,
7970         /** Key constant 
7971         * @type Number */
7972         END : 35,
7973         /** Key constant 
7974         * @type Number */
7975         HOME : 36,
7976         /** Key constant 
7977         * @type Number */
7978         LEFT : 37,
7979         /** Key constant 
7980         * @type Number */
7981         UP : 38,
7982         /** Key constant 
7983         * @type Number */
7984         RIGHT : 39,
7985         /** Key constant 
7986         * @type Number */
7987         DOWN : 40,
7988         /** Key constant 
7989         * @type Number */
7990         DELETE : 46,
7991         /** Key constant 
7992         * @type Number */
7993         F5 : 116,
7994
7995            /** @private */
7996         setEvent : function(e){
7997             if(e == this || (e && e.browserEvent)){ // already wrapped
7998                 return e;
7999             }
8000             this.browserEvent = e;
8001             if(e){
8002                 // normalize buttons
8003                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
8004                 if(e.type == 'click' && this.button == -1){
8005                     this.button = 0;
8006                 }
8007                 this.type = e.type;
8008                 this.shiftKey = e.shiftKey;
8009                 // mac metaKey behaves like ctrlKey
8010                 this.ctrlKey = e.ctrlKey || e.metaKey;
8011                 this.altKey = e.altKey;
8012                 // in getKey these will be normalized for the mac
8013                 this.keyCode = e.keyCode;
8014                 // keyup warnings on firefox.
8015                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
8016                 // cache the target for the delayed and or buffered events
8017                 this.target = E.getTarget(e);
8018                 // same for XY
8019                 this.xy = E.getXY(e);
8020             }else{
8021                 this.button = -1;
8022                 this.shiftKey = false;
8023                 this.ctrlKey = false;
8024                 this.altKey = false;
8025                 this.keyCode = 0;
8026                 this.charCode =0;
8027                 this.target = null;
8028                 this.xy = [0, 0];
8029             }
8030             return this;
8031         },
8032
8033         /**
8034          * Stop the event (preventDefault and stopPropagation)
8035          */
8036         stopEvent : function(){
8037             if(this.browserEvent){
8038                 if(this.browserEvent.type == 'mousedown'){
8039                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
8040                 }
8041                 E.stopEvent(this.browserEvent);
8042             }
8043         },
8044
8045         /**
8046          * Prevents the browsers default handling of the event.
8047          */
8048         preventDefault : function(){
8049             if(this.browserEvent){
8050                 E.preventDefault(this.browserEvent);
8051             }
8052         },
8053
8054         /** @private */
8055         isNavKeyPress : function(){
8056             var k = this.keyCode;
8057             k = Roo.isSafari ? (safariKeys[k] || k) : k;
8058             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
8059         },
8060
8061         isSpecialKey : function(){
8062             var k = this.keyCode;
8063             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
8064             (k == 16) || (k == 17) ||
8065             (k >= 18 && k <= 20) ||
8066             (k >= 33 && k <= 35) ||
8067             (k >= 36 && k <= 39) ||
8068             (k >= 44 && k <= 45);
8069         },
8070         /**
8071          * Cancels bubbling of the event.
8072          */
8073         stopPropagation : function(){
8074             if(this.browserEvent){
8075                 if(this.type == 'mousedown'){
8076                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
8077                 }
8078                 E.stopPropagation(this.browserEvent);
8079             }
8080         },
8081
8082         /**
8083          * Gets the key code for the event.
8084          * @return {Number}
8085          */
8086         getCharCode : function(){
8087             return this.charCode || this.keyCode;
8088         },
8089
8090         /**
8091          * Returns a normalized keyCode for the event.
8092          * @return {Number} The key code
8093          */
8094         getKey : function(){
8095             var k = this.keyCode || this.charCode;
8096             return Roo.isSafari ? (safariKeys[k] || k) : k;
8097         },
8098
8099         /**
8100          * Gets the x coordinate of the event.
8101          * @return {Number}
8102          */
8103         getPageX : function(){
8104             return this.xy[0];
8105         },
8106
8107         /**
8108          * Gets the y coordinate of the event.
8109          * @return {Number}
8110          */
8111         getPageY : function(){
8112             return this.xy[1];
8113         },
8114
8115         /**
8116          * Gets the time of the event.
8117          * @return {Number}
8118          */
8119         getTime : function(){
8120             if(this.browserEvent){
8121                 return E.getTime(this.browserEvent);
8122             }
8123             return null;
8124         },
8125
8126         /**
8127          * Gets the page coordinates of the event.
8128          * @return {Array} The xy values like [x, y]
8129          */
8130         getXY : function(){
8131             return this.xy;
8132         },
8133
8134         /**
8135          * Gets the target for the event.
8136          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
8137          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8138                 search as a number or element (defaults to 10 || document.body)
8139          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
8140          * @return {HTMLelement}
8141          */
8142         getTarget : function(selector, maxDepth, returnEl){
8143             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
8144         },
8145         /**
8146          * Gets the related target.
8147          * @return {HTMLElement}
8148          */
8149         getRelatedTarget : function(){
8150             if(this.browserEvent){
8151                 return E.getRelatedTarget(this.browserEvent);
8152             }
8153             return null;
8154         },
8155
8156         /**
8157          * Normalizes mouse wheel delta across browsers
8158          * @return {Number} The delta
8159          */
8160         getWheelDelta : function(){
8161             var e = this.browserEvent;
8162             var delta = 0;
8163             if(e.wheelDelta){ /* IE/Opera. */
8164                 delta = e.wheelDelta/120;
8165             }else if(e.detail){ /* Mozilla case. */
8166                 delta = -e.detail/3;
8167             }
8168             return delta;
8169         },
8170
8171         /**
8172          * Returns true if the control, meta, shift or alt key was pressed during this event.
8173          * @return {Boolean}
8174          */
8175         hasModifier : function(){
8176             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
8177         },
8178
8179         /**
8180          * Returns true if the target of this event equals el or is a child of el
8181          * @param {String/HTMLElement/Element} el
8182          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
8183          * @return {Boolean}
8184          */
8185         within : function(el, related){
8186             var t = this[related ? "getRelatedTarget" : "getTarget"]();
8187             return t && Roo.fly(el).contains(t);
8188         },
8189
8190         getPoint : function(){
8191             return new Roo.lib.Point(this.xy[0], this.xy[1]);
8192         }
8193     };
8194
8195     return new Roo.EventObjectImpl();
8196 }();
8197             
8198     /*
8199  * Based on:
8200  * Ext JS Library 1.1.1
8201  * Copyright(c) 2006-2007, Ext JS, LLC.
8202  *
8203  * Originally Released Under LGPL - original licence link has changed is not relivant.
8204  *
8205  * Fork - LGPL
8206  * <script type="text/javascript">
8207  */
8208
8209  
8210 // was in Composite Element!??!?!
8211  
8212 (function(){
8213     var D = Roo.lib.Dom;
8214     var E = Roo.lib.Event;
8215     var A = Roo.lib.Anim;
8216
8217     // local style camelizing for speed
8218     var propCache = {};
8219     var camelRe = /(-[a-z])/gi;
8220     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
8221     var view = document.defaultView;
8222
8223 /**
8224  * @class Roo.Element
8225  * Represents an Element in the DOM.<br><br>
8226  * Usage:<br>
8227 <pre><code>
8228 var el = Roo.get("my-div");
8229
8230 // or with getEl
8231 var el = getEl("my-div");
8232
8233 // or with a DOM element
8234 var el = Roo.get(myDivElement);
8235 </code></pre>
8236  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
8237  * each call instead of constructing a new one.<br><br>
8238  * <b>Animations</b><br />
8239  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
8240  * should either be a boolean (true) or an object literal with animation options. The animation options are:
8241 <pre>
8242 Option    Default   Description
8243 --------- --------  ---------------------------------------------
8244 duration  .35       The duration of the animation in seconds
8245 easing    easeOut   The YUI easing method
8246 callback  none      A function to execute when the anim completes
8247 scope     this      The scope (this) of the callback function
8248 </pre>
8249 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
8250 * manipulate the animation. Here's an example:
8251 <pre><code>
8252 var el = Roo.get("my-div");
8253
8254 // no animation
8255 el.setWidth(100);
8256
8257 // default animation
8258 el.setWidth(100, true);
8259
8260 // animation with some options set
8261 el.setWidth(100, {
8262     duration: 1,
8263     callback: this.foo,
8264     scope: this
8265 });
8266
8267 // using the "anim" property to get the Anim object
8268 var opt = {
8269     duration: 1,
8270     callback: this.foo,
8271     scope: this
8272 };
8273 el.setWidth(100, opt);
8274 ...
8275 if(opt.anim.isAnimated()){
8276     opt.anim.stop();
8277 }
8278 </code></pre>
8279 * <b> Composite (Collections of) Elements</b><br />
8280  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
8281  * @constructor Create a new Element directly.
8282  * @param {String/HTMLElement} element
8283  * @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).
8284  */
8285     Roo.Element = function(element, forceNew)
8286     {
8287         var dom = typeof element == "string" ?
8288                 document.getElementById(element) : element;
8289         
8290         this.listeners = {};
8291         
8292         if(!dom){ // invalid id/element
8293             return null;
8294         }
8295         var id = dom.id;
8296         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
8297             return Roo.Element.cache[id];
8298         }
8299
8300         /**
8301          * The DOM element
8302          * @type HTMLElement
8303          */
8304         this.dom = dom;
8305
8306         /**
8307          * The DOM element ID
8308          * @type String
8309          */
8310         this.id = id || Roo.id(dom);
8311         
8312         return this; // assumed for cctor?
8313     };
8314
8315     var El = Roo.Element;
8316
8317     El.prototype = {
8318         /**
8319          * The element's default display mode  (defaults to "") 
8320          * @type String
8321          */
8322         originalDisplay : "",
8323
8324         
8325         // note this is overridden in BS version..
8326         visibilityMode : 1, 
8327         /**
8328          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
8329          * @type String
8330          */
8331         defaultUnit : "px",
8332         
8333         /**
8334          * Sets the element's visibility mode. When setVisible() is called it
8335          * will use this to determine whether to set the visibility or the display property.
8336          * @param visMode Element.VISIBILITY or Element.DISPLAY
8337          * @return {Roo.Element} this
8338          */
8339         setVisibilityMode : function(visMode){
8340             this.visibilityMode = visMode;
8341             return this;
8342         },
8343         /**
8344          * Convenience method for setVisibilityMode(Element.DISPLAY)
8345          * @param {String} display (optional) What to set display to when visible
8346          * @return {Roo.Element} this
8347          */
8348         enableDisplayMode : function(display){
8349             this.setVisibilityMode(El.DISPLAY);
8350             if(typeof display != "undefined") { this.originalDisplay = display; }
8351             return this;
8352         },
8353
8354         /**
8355          * 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)
8356          * @param {String} selector The simple selector to test
8357          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8358                 search as a number or element (defaults to 10 || document.body)
8359          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
8360          * @return {HTMLElement} The matching DOM node (or null if no match was found)
8361          */
8362         findParent : function(simpleSelector, maxDepth, returnEl){
8363             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
8364             maxDepth = maxDepth || 50;
8365             if(typeof maxDepth != "number"){
8366                 stopEl = Roo.getDom(maxDepth);
8367                 maxDepth = 10;
8368             }
8369             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
8370                 if(dq.is(p, simpleSelector)){
8371                     return returnEl ? Roo.get(p) : p;
8372                 }
8373                 depth++;
8374                 p = p.parentNode;
8375             }
8376             return null;
8377         },
8378
8379
8380         /**
8381          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
8382          * @param {String} selector The simple selector to test
8383          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8384                 search as a number or element (defaults to 10 || document.body)
8385          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
8386          * @return {HTMLElement} The matching DOM node (or null if no match was found)
8387          */
8388         findParentNode : function(simpleSelector, maxDepth, returnEl){
8389             var p = Roo.fly(this.dom.parentNode, '_internal');
8390             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
8391         },
8392         
8393         /**
8394          * Looks at  the scrollable parent element
8395          */
8396         findScrollableParent : function()
8397         {
8398             var overflowRegex = /(auto|scroll)/;
8399             
8400             if(this.getStyle('position') === 'fixed'){
8401                 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
8402             }
8403             
8404             var excludeStaticParent = this.getStyle('position') === "absolute";
8405             
8406             for (var parent = this; (parent = Roo.get(parent.dom.parentNode));){
8407                 
8408                 if (excludeStaticParent && parent.getStyle('position') === "static") {
8409                     continue;
8410                 }
8411                 
8412                 if (overflowRegex.test(parent.getStyle('overflow') + parent.getStyle('overflow-x') + parent.getStyle('overflow-y'))){
8413                     return parent;
8414                 }
8415                 
8416                 if(parent.dom.nodeName.toLowerCase() == 'body'){
8417                     return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
8418                 }
8419             }
8420             
8421             return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
8422         },
8423
8424         /**
8425          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
8426          * This is a shortcut for findParentNode() that always returns an Roo.Element.
8427          * @param {String} selector The simple selector to test
8428          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8429                 search as a number or element (defaults to 10 || document.body)
8430          * @return {Roo.Element} The matching DOM node (or null if no match was found)
8431          */
8432         up : function(simpleSelector, maxDepth){
8433             return this.findParentNode(simpleSelector, maxDepth, true);
8434         },
8435
8436
8437
8438         /**
8439          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
8440          * @param {String} selector The simple selector to test
8441          * @return {Boolean} True if this element matches the selector, else false
8442          */
8443         is : function(simpleSelector){
8444             return Roo.DomQuery.is(this.dom, simpleSelector);
8445         },
8446
8447         /**
8448          * Perform animation on this element.
8449          * @param {Object} args The YUI animation control args
8450          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
8451          * @param {Function} onComplete (optional) Function to call when animation completes
8452          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
8453          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
8454          * @return {Roo.Element} this
8455          */
8456         animate : function(args, duration, onComplete, easing, animType){
8457             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
8458             return this;
8459         },
8460
8461         /*
8462          * @private Internal animation call
8463          */
8464         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
8465             animType = animType || 'run';
8466             opt = opt || {};
8467             var anim = Roo.lib.Anim[animType](
8468                 this.dom, args,
8469                 (opt.duration || defaultDur) || .35,
8470                 (opt.easing || defaultEase) || 'easeOut',
8471                 function(){
8472                     Roo.callback(cb, this);
8473                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
8474                 },
8475                 this
8476             );
8477             opt.anim = anim;
8478             return anim;
8479         },
8480
8481         // private legacy anim prep
8482         preanim : function(a, i){
8483             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
8484         },
8485
8486         /**
8487          * Removes worthless text nodes
8488          * @param {Boolean} forceReclean (optional) By default the element
8489          * keeps track if it has been cleaned already so
8490          * you can call this over and over. However, if you update the element and
8491          * need to force a reclean, you can pass true.
8492          */
8493         clean : function(forceReclean){
8494             if(this.isCleaned && forceReclean !== true){
8495                 return this;
8496             }
8497             var ns = /\S/;
8498             var d = this.dom, n = d.firstChild, ni = -1;
8499             while(n){
8500                 var nx = n.nextSibling;
8501                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
8502                     d.removeChild(n);
8503                 }else{
8504                     n.nodeIndex = ++ni;
8505                 }
8506                 n = nx;
8507             }
8508             this.isCleaned = true;
8509             return this;
8510         },
8511
8512         // private
8513         calcOffsetsTo : function(el){
8514             el = Roo.get(el);
8515             var d = el.dom;
8516             var restorePos = false;
8517             if(el.getStyle('position') == 'static'){
8518                 el.position('relative');
8519                 restorePos = true;
8520             }
8521             var x = 0, y =0;
8522             var op = this.dom;
8523             while(op && op != d && op.tagName != 'HTML'){
8524                 x+= op.offsetLeft;
8525                 y+= op.offsetTop;
8526                 op = op.offsetParent;
8527             }
8528             if(restorePos){
8529                 el.position('static');
8530             }
8531             return [x, y];
8532         },
8533
8534         /**
8535          * Scrolls this element into view within the passed container.
8536          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
8537          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
8538          * @return {Roo.Element} this
8539          */
8540         scrollIntoView : function(container, hscroll){
8541             var c = Roo.getDom(container) || document.body;
8542             var el = this.dom;
8543
8544             var o = this.calcOffsetsTo(c),
8545                 l = o[0],
8546                 t = o[1],
8547                 b = t+el.offsetHeight,
8548                 r = l+el.offsetWidth;
8549
8550             var ch = c.clientHeight;
8551             var ct = parseInt(c.scrollTop, 10);
8552             var cl = parseInt(c.scrollLeft, 10);
8553             var cb = ct + ch;
8554             var cr = cl + c.clientWidth;
8555
8556             if(t < ct){
8557                 c.scrollTop = t;
8558             }else if(b > cb){
8559                 c.scrollTop = b-ch;
8560             }
8561
8562             if(hscroll !== false){
8563                 if(l < cl){
8564                     c.scrollLeft = l;
8565                 }else if(r > cr){
8566                     c.scrollLeft = r-c.clientWidth;
8567                 }
8568             }
8569             return this;
8570         },
8571
8572         // private
8573         scrollChildIntoView : function(child, hscroll){
8574             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
8575         },
8576
8577         /**
8578          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
8579          * the new height may not be available immediately.
8580          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
8581          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
8582          * @param {Function} onComplete (optional) Function to call when animation completes
8583          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
8584          * @return {Roo.Element} this
8585          */
8586         autoHeight : function(animate, duration, onComplete, easing){
8587             var oldHeight = this.getHeight();
8588             this.clip();
8589             this.setHeight(1); // force clipping
8590             setTimeout(function(){
8591                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
8592                 if(!animate){
8593                     this.setHeight(height);
8594                     this.unclip();
8595                     if(typeof onComplete == "function"){
8596                         onComplete();
8597                     }
8598                 }else{
8599                     this.setHeight(oldHeight); // restore original height
8600                     this.setHeight(height, animate, duration, function(){
8601                         this.unclip();
8602                         if(typeof onComplete == "function") { onComplete(); }
8603                     }.createDelegate(this), easing);
8604                 }
8605             }.createDelegate(this), 0);
8606             return this;
8607         },
8608
8609         /**
8610          * Returns true if this element is an ancestor of the passed element
8611          * @param {HTMLElement/String} el The element to check
8612          * @return {Boolean} True if this element is an ancestor of el, else false
8613          */
8614         contains : function(el){
8615             if(!el){return false;}
8616             return D.isAncestor(this.dom, el.dom ? el.dom : el);
8617         },
8618
8619         /**
8620          * Checks whether the element is currently visible using both visibility and display properties.
8621          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
8622          * @return {Boolean} True if the element is currently visible, else false
8623          */
8624         isVisible : function(deep) {
8625             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
8626             if(deep !== true || !vis){
8627                 return vis;
8628             }
8629             var p = this.dom.parentNode;
8630             while(p && p.tagName.toLowerCase() != "body"){
8631                 if(!Roo.fly(p, '_isVisible').isVisible()){
8632                     return false;
8633                 }
8634                 p = p.parentNode;
8635             }
8636             return true;
8637         },
8638
8639         /**
8640          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
8641          * @param {String} selector The CSS selector
8642          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
8643          * @return {CompositeElement/CompositeElementLite} The composite element
8644          */
8645         select : function(selector, unique){
8646             return El.select(selector, unique, this.dom);
8647         },
8648
8649         /**
8650          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
8651          * @param {String} selector The CSS selector
8652          * @return {Array} An array of the matched nodes
8653          */
8654         query : function(selector, unique){
8655             return Roo.DomQuery.select(selector, this.dom);
8656         },
8657
8658         /**
8659          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
8660          * @param {String} selector The CSS selector
8661          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
8662          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
8663          */
8664         child : function(selector, returnDom){
8665             var n = Roo.DomQuery.selectNode(selector, this.dom);
8666             return returnDom ? n : Roo.get(n);
8667         },
8668
8669         /**
8670          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
8671          * @param {String} selector The CSS selector
8672          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
8673          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
8674          */
8675         down : function(selector, returnDom){
8676             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
8677             return returnDom ? n : Roo.get(n);
8678         },
8679
8680         /**
8681          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
8682          * @param {String} group The group the DD object is member of
8683          * @param {Object} config The DD config object
8684          * @param {Object} overrides An object containing methods to override/implement on the DD object
8685          * @return {Roo.dd.DD} The DD object
8686          */
8687         initDD : function(group, config, overrides){
8688             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
8689             return Roo.apply(dd, overrides);
8690         },
8691
8692         /**
8693          * Initializes a {@link Roo.dd.DDProxy} object for this element.
8694          * @param {String} group The group the DDProxy object is member of
8695          * @param {Object} config The DDProxy config object
8696          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
8697          * @return {Roo.dd.DDProxy} The DDProxy object
8698          */
8699         initDDProxy : function(group, config, overrides){
8700             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
8701             return Roo.apply(dd, overrides);
8702         },
8703
8704         /**
8705          * Initializes a {@link Roo.dd.DDTarget} object for this element.
8706          * @param {String} group The group the DDTarget object is member of
8707          * @param {Object} config The DDTarget config object
8708          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
8709          * @return {Roo.dd.DDTarget} The DDTarget object
8710          */
8711         initDDTarget : function(group, config, overrides){
8712             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
8713             return Roo.apply(dd, overrides);
8714         },
8715
8716         /**
8717          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
8718          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
8719          * @param {Boolean} visible Whether the element is visible
8720          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8721          * @return {Roo.Element} this
8722          */
8723          setVisible : function(visible, animate){
8724             if(!animate || !A){
8725                 if(this.visibilityMode == El.DISPLAY){
8726                     this.setDisplayed(visible);
8727                 }else{
8728                     this.fixDisplay();
8729                     this.dom.style.visibility = visible ? "visible" : "hidden";
8730                 }
8731             }else{
8732                 // closure for composites
8733                 var dom = this.dom;
8734                 var visMode = this.visibilityMode;
8735                 if(visible){
8736                     this.setOpacity(.01);
8737                     this.setVisible(true);
8738                 }
8739                 this.anim({opacity: { to: (visible?1:0) }},
8740                       this.preanim(arguments, 1),
8741                       null, .35, 'easeIn', function(){
8742                          if(!visible){
8743                              if(visMode == El.DISPLAY){
8744                                  dom.style.display = "none";
8745                              }else{
8746                                  dom.style.visibility = "hidden";
8747                              }
8748                              Roo.get(dom).setOpacity(1);
8749                          }
8750                      });
8751             }
8752             return this;
8753         },
8754
8755         /**
8756          * Returns true if display is not "none"
8757          * @return {Boolean}
8758          */
8759         isDisplayed : function() {
8760             return this.getStyle("display") != "none";
8761         },
8762
8763         /**
8764          * Toggles the element's visibility or display, depending on visibility mode.
8765          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8766          * @return {Roo.Element} this
8767          */
8768         toggle : function(animate){
8769             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
8770             return this;
8771         },
8772
8773         /**
8774          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
8775          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
8776          * @return {Roo.Element} this
8777          */
8778         setDisplayed : function(value) {
8779             if(typeof value == "boolean"){
8780                value = value ? this.originalDisplay : "none";
8781             }
8782             this.setStyle("display", value);
8783             return this;
8784         },
8785
8786         /**
8787          * Tries to focus the element. Any exceptions are caught and ignored.
8788          * @return {Roo.Element} this
8789          */
8790         focus : function() {
8791             try{
8792                 this.dom.focus();
8793             }catch(e){}
8794             return this;
8795         },
8796
8797         /**
8798          * Tries to blur the element. Any exceptions are caught and ignored.
8799          * @return {Roo.Element} this
8800          */
8801         blur : function() {
8802             try{
8803                 this.dom.blur();
8804             }catch(e){}
8805             return this;
8806         },
8807
8808         /**
8809          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
8810          * @param {String/Array} className The CSS class to add, or an array of classes
8811          * @return {Roo.Element} this
8812          */
8813         addClass : function(className){
8814             if(className instanceof Array){
8815                 for(var i = 0, len = className.length; i < len; i++) {
8816                     this.addClass(className[i]);
8817                 }
8818             }else{
8819                 if(className && !this.hasClass(className)){
8820                     if (this.dom instanceof SVGElement) {
8821                         this.dom.className.baseVal =this.dom.className.baseVal  + " " + className;
8822                     } else {
8823                         this.dom.className = this.dom.className + " " + className;
8824                     }
8825                 }
8826             }
8827             return this;
8828         },
8829
8830         /**
8831          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
8832          * @param {String/Array} className The CSS class to add, or an array of classes
8833          * @return {Roo.Element} this
8834          */
8835         radioClass : function(className){
8836             var siblings = this.dom.parentNode.childNodes;
8837             for(var i = 0; i < siblings.length; i++) {
8838                 var s = siblings[i];
8839                 if(s.nodeType == 1){
8840                     Roo.get(s).removeClass(className);
8841                 }
8842             }
8843             this.addClass(className);
8844             return this;
8845         },
8846
8847         /**
8848          * Removes one or more CSS classes from the element.
8849          * @param {String/Array} className The CSS class to remove, or an array of classes
8850          * @return {Roo.Element} this
8851          */
8852         removeClass : function(className){
8853             
8854             var cn = this.dom instanceof SVGElement ? this.dom.className.baseVal : this.dom.className;
8855             if(!className || !cn){
8856                 return this;
8857             }
8858             if(className instanceof Array){
8859                 for(var i = 0, len = className.length; i < len; i++) {
8860                     this.removeClass(className[i]);
8861                 }
8862             }else{
8863                 if(this.hasClass(className)){
8864                     var re = this.classReCache[className];
8865                     if (!re) {
8866                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
8867                        this.classReCache[className] = re;
8868                     }
8869                     if (this.dom instanceof SVGElement) {
8870                         this.dom.className.baseVal = cn.replace(re, " ");
8871                     } else {
8872                         this.dom.className = cn.replace(re, " ");
8873                     }
8874                 }
8875             }
8876             return this;
8877         },
8878
8879         // private
8880         classReCache: {},
8881
8882         /**
8883          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
8884          * @param {String} className The CSS class to toggle
8885          * @return {Roo.Element} this
8886          */
8887         toggleClass : function(className){
8888             if(this.hasClass(className)){
8889                 this.removeClass(className);
8890             }else{
8891                 this.addClass(className);
8892             }
8893             return this;
8894         },
8895
8896         /**
8897          * Checks if the specified CSS class exists on this element's DOM node.
8898          * @param {String} className The CSS class to check for
8899          * @return {Boolean} True if the class exists, else false
8900          */
8901         hasClass : function(className){
8902             if (this.dom instanceof SVGElement) {
8903                 return className && (' '+this.dom.className.baseVal +' ').indexOf(' '+className+' ') != -1; 
8904             } 
8905             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
8906         },
8907
8908         /**
8909          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
8910          * @param {String} oldClassName The CSS class to replace
8911          * @param {String} newClassName The replacement CSS class
8912          * @return {Roo.Element} this
8913          */
8914         replaceClass : function(oldClassName, newClassName){
8915             this.removeClass(oldClassName);
8916             this.addClass(newClassName);
8917             return this;
8918         },
8919
8920         /**
8921          * Returns an object with properties matching the styles requested.
8922          * For example, el.getStyles('color', 'font-size', 'width') might return
8923          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
8924          * @param {String} style1 A style name
8925          * @param {String} style2 A style name
8926          * @param {String} etc.
8927          * @return {Object} The style object
8928          */
8929         getStyles : function(){
8930             var a = arguments, len = a.length, r = {};
8931             for(var i = 0; i < len; i++){
8932                 r[a[i]] = this.getStyle(a[i]);
8933             }
8934             return r;
8935         },
8936
8937         /**
8938          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
8939          * @param {String} property The style property whose value is returned.
8940          * @return {String} The current value of the style property for this element.
8941          */
8942         getStyle : function(){
8943             return view && view.getComputedStyle ?
8944                 function(prop){
8945                     var el = this.dom, v, cs, camel;
8946                     if(prop == 'float'){
8947                         prop = "cssFloat";
8948                     }
8949                     if(el.style && (v = el.style[prop])){
8950                         return v;
8951                     }
8952                     if(cs = view.getComputedStyle(el, "")){
8953                         if(!(camel = propCache[prop])){
8954                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
8955                         }
8956                         return cs[camel];
8957                     }
8958                     return null;
8959                 } :
8960                 function(prop){
8961                     var el = this.dom, v, cs, camel;
8962                     if(prop == 'opacity'){
8963                         if(typeof el.style.filter == 'string'){
8964                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
8965                             if(m){
8966                                 var fv = parseFloat(m[1]);
8967                                 if(!isNaN(fv)){
8968                                     return fv ? fv / 100 : 0;
8969                                 }
8970                             }
8971                         }
8972                         return 1;
8973                     }else if(prop == 'float'){
8974                         prop = "styleFloat";
8975                     }
8976                     if(!(camel = propCache[prop])){
8977                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
8978                     }
8979                     if(v = el.style[camel]){
8980                         return v;
8981                     }
8982                     if(cs = el.currentStyle){
8983                         return cs[camel];
8984                     }
8985                     return null;
8986                 };
8987         }(),
8988
8989         /**
8990          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
8991          * @param {String/Object} property The style property to be set, or an object of multiple styles.
8992          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
8993          * @return {Roo.Element} this
8994          */
8995         setStyle : function(prop, value){
8996             if(typeof prop == "string"){
8997                 
8998                 if (prop == 'float') {
8999                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
9000                     return this;
9001                 }
9002                 
9003                 var camel;
9004                 if(!(camel = propCache[prop])){
9005                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
9006                 }
9007                 
9008                 if(camel == 'opacity') {
9009                     this.setOpacity(value);
9010                 }else{
9011                     this.dom.style[camel] = value;
9012                 }
9013             }else{
9014                 for(var style in prop){
9015                     if(typeof prop[style] != "function"){
9016                        this.setStyle(style, prop[style]);
9017                     }
9018                 }
9019             }
9020             return this;
9021         },
9022
9023         /**
9024          * More flexible version of {@link #setStyle} for setting style properties.
9025          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
9026          * a function which returns such a specification.
9027          * @return {Roo.Element} this
9028          */
9029         applyStyles : function(style){
9030             Roo.DomHelper.applyStyles(this.dom, style);
9031             return this;
9032         },
9033
9034         /**
9035           * 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).
9036           * @return {Number} The X position of the element
9037           */
9038         getX : function(){
9039             return D.getX(this.dom);
9040         },
9041
9042         /**
9043           * 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).
9044           * @return {Number} The Y position of the element
9045           */
9046         getY : function(){
9047             return D.getY(this.dom);
9048         },
9049
9050         /**
9051           * 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).
9052           * @return {Array} The XY position of the element
9053           */
9054         getXY : function(){
9055             return D.getXY(this.dom);
9056         },
9057
9058         /**
9059          * 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).
9060          * @param {Number} The X position of the element
9061          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
9062          * @return {Roo.Element} this
9063          */
9064         setX : function(x, animate){
9065             if(!animate || !A){
9066                 D.setX(this.dom, x);
9067             }else{
9068                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
9069             }
9070             return this;
9071         },
9072
9073         /**
9074          * 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).
9075          * @param {Number} The Y position of the element
9076          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
9077          * @return {Roo.Element} this
9078          */
9079         setY : function(y, animate){
9080             if(!animate || !A){
9081                 D.setY(this.dom, y);
9082             }else{
9083                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
9084             }
9085             return this;
9086         },
9087
9088         /**
9089          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
9090          * @param {String} left The left CSS property value
9091          * @return {Roo.Element} this
9092          */
9093         setLeft : function(left){
9094             this.setStyle("left", this.addUnits(left));
9095             return this;
9096         },
9097
9098         /**
9099          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
9100          * @param {String} top The top CSS property value
9101          * @return {Roo.Element} this
9102          */
9103         setTop : function(top){
9104             this.setStyle("top", this.addUnits(top));
9105             return this;
9106         },
9107
9108         /**
9109          * Sets the element's CSS right style.
9110          * @param {String} right The right CSS property value
9111          * @return {Roo.Element} this
9112          */
9113         setRight : function(right){
9114             this.setStyle("right", this.addUnits(right));
9115             return this;
9116         },
9117
9118         /**
9119          * Sets the element's CSS bottom style.
9120          * @param {String} bottom The bottom CSS property value
9121          * @return {Roo.Element} this
9122          */
9123         setBottom : function(bottom){
9124             this.setStyle("bottom", this.addUnits(bottom));
9125             return this;
9126         },
9127
9128         /**
9129          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
9130          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
9131          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
9132          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
9133          * @return {Roo.Element} this
9134          */
9135         setXY : function(pos, animate){
9136             if(!animate || !A){
9137                 D.setXY(this.dom, pos);
9138             }else{
9139                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
9140             }
9141             return this;
9142         },
9143
9144         /**
9145          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
9146          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
9147          * @param {Number} x X value for new position (coordinates are page-based)
9148          * @param {Number} y Y value for new position (coordinates are page-based)
9149          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
9150          * @return {Roo.Element} this
9151          */
9152         setLocation : function(x, y, animate){
9153             this.setXY([x, y], this.preanim(arguments, 2));
9154             return this;
9155         },
9156
9157         /**
9158          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
9159          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
9160          * @param {Number} x X value for new position (coordinates are page-based)
9161          * @param {Number} y Y value for new position (coordinates are page-based)
9162          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
9163          * @return {Roo.Element} this
9164          */
9165         moveTo : function(x, y, animate){
9166             this.setXY([x, y], this.preanim(arguments, 2));
9167             return this;
9168         },
9169
9170         /**
9171          * Returns the region of the given element.
9172          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
9173          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
9174          */
9175         getRegion : function(){
9176             return D.getRegion(this.dom);
9177         },
9178
9179         /**
9180          * Returns the offset height of the element
9181          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
9182          * @return {Number} The element's height
9183          */
9184         getHeight : function(contentHeight){
9185             var h = this.dom.offsetHeight || 0;
9186             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
9187         },
9188
9189         /**
9190          * Returns the offset width of the element
9191          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
9192          * @return {Number} The element's width
9193          */
9194         getWidth : function(contentWidth){
9195             var w = this.dom.offsetWidth || 0;
9196             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
9197         },
9198
9199         /**
9200          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
9201          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
9202          * if a height has not been set using CSS.
9203          * @return {Number}
9204          */
9205         getComputedHeight : function(){
9206             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
9207             if(!h){
9208                 h = parseInt(this.getStyle('height'), 10) || 0;
9209                 if(!this.isBorderBox()){
9210                     h += this.getFrameWidth('tb');
9211                 }
9212             }
9213             return h;
9214         },
9215
9216         /**
9217          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
9218          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
9219          * if a width has not been set using CSS.
9220          * @return {Number}
9221          */
9222         getComputedWidth : function(){
9223             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
9224             if(!w){
9225                 w = parseInt(this.getStyle('width'), 10) || 0;
9226                 if(!this.isBorderBox()){
9227                     w += this.getFrameWidth('lr');
9228                 }
9229             }
9230             return w;
9231         },
9232
9233         /**
9234          * Returns the size of the element.
9235          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
9236          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
9237          */
9238         getSize : function(contentSize){
9239             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
9240         },
9241
9242         /**
9243          * Returns the width and height of the viewport.
9244          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
9245          */
9246         getViewSize : function(){
9247             var d = this.dom, doc = document, aw = 0, ah = 0;
9248             if(d == doc || d == doc.body){
9249                 return {width : D.getViewWidth(), height: D.getViewHeight()};
9250             }else{
9251                 return {
9252                     width : d.clientWidth,
9253                     height: d.clientHeight
9254                 };
9255             }
9256         },
9257
9258         /**
9259          * Returns the value of the "value" attribute
9260          * @param {Boolean} asNumber true to parse the value as a number
9261          * @return {String/Number}
9262          */
9263         getValue : function(asNumber){
9264             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
9265         },
9266
9267         // private
9268         adjustWidth : function(width){
9269             if(typeof width == "number"){
9270                 if(this.autoBoxAdjust && !this.isBorderBox()){
9271                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
9272                 }
9273                 if(width < 0){
9274                     width = 0;
9275                 }
9276             }
9277             return width;
9278         },
9279
9280         // private
9281         adjustHeight : function(height){
9282             if(typeof height == "number"){
9283                if(this.autoBoxAdjust && !this.isBorderBox()){
9284                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
9285                }
9286                if(height < 0){
9287                    height = 0;
9288                }
9289             }
9290             return height;
9291         },
9292
9293         /**
9294          * Set the width of the element
9295          * @param {Number} width The new width
9296          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9297          * @return {Roo.Element} this
9298          */
9299         setWidth : function(width, animate){
9300             width = this.adjustWidth(width);
9301             if(!animate || !A){
9302                 this.dom.style.width = this.addUnits(width);
9303             }else{
9304                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
9305             }
9306             return this;
9307         },
9308
9309         /**
9310          * Set the height of the element
9311          * @param {Number} height The new height
9312          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9313          * @return {Roo.Element} this
9314          */
9315          setHeight : function(height, animate){
9316             height = this.adjustHeight(height);
9317             if(!animate || !A){
9318                 this.dom.style.height = this.addUnits(height);
9319             }else{
9320                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
9321             }
9322             return this;
9323         },
9324
9325         /**
9326          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
9327          * @param {Number} width The new width
9328          * @param {Number} height The new height
9329          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9330          * @return {Roo.Element} this
9331          */
9332          setSize : function(width, height, animate){
9333             if(typeof width == "object"){ // in case of object from getSize()
9334                 height = width.height; width = width.width;
9335             }
9336             width = this.adjustWidth(width); height = this.adjustHeight(height);
9337             if(!animate || !A){
9338                 this.dom.style.width = this.addUnits(width);
9339                 this.dom.style.height = this.addUnits(height);
9340             }else{
9341                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
9342             }
9343             return this;
9344         },
9345
9346         /**
9347          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
9348          * @param {Number} x X value for new position (coordinates are page-based)
9349          * @param {Number} y Y value for new position (coordinates are page-based)
9350          * @param {Number} width The new width
9351          * @param {Number} height The new height
9352          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9353          * @return {Roo.Element} this
9354          */
9355         setBounds : function(x, y, width, height, animate){
9356             if(!animate || !A){
9357                 this.setSize(width, height);
9358                 this.setLocation(x, y);
9359             }else{
9360                 width = this.adjustWidth(width); height = this.adjustHeight(height);
9361                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
9362                               this.preanim(arguments, 4), 'motion');
9363             }
9364             return this;
9365         },
9366
9367         /**
9368          * 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.
9369          * @param {Roo.lib.Region} region The region to fill
9370          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9371          * @return {Roo.Element} this
9372          */
9373         setRegion : function(region, animate){
9374             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
9375             return this;
9376         },
9377
9378         /**
9379          * Appends an event handler
9380          *
9381          * @param {String}   eventName     The type of event to append
9382          * @param {Function} fn        The method the event invokes
9383          * @param {Object} scope       (optional) The scope (this object) of the fn
9384          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9385          */
9386         addListener : function(eventName, fn, scope, options)
9387         {
9388             if (eventName == 'dblclick') { // doublclick (touchstart) - faked on touch.
9389                 this.addListener('touchstart', this.onTapHandler, this);
9390             }
9391             
9392             // we need to handle a special case where dom element is a svg element.
9393             // in this case we do not actua
9394             if (!this.dom) {
9395                 return;
9396             }
9397             
9398             if (this.dom instanceof SVGElement && !(this.dom instanceof SVGSVGElement)) {
9399                 if (typeof(this.listeners[eventName]) == 'undefined') {
9400                     this.listeners[eventName] =  new Roo.util.Event(this, eventName);
9401                 }
9402                 this.listeners[eventName].addListener(fn, scope, options);
9403                 return;
9404             }
9405             
9406                 
9407             Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
9408             
9409             
9410         },
9411         tapedTwice : false,
9412         onTapHandler : function(event)
9413         {
9414             if(!this.tapedTwice) {
9415                 this.tapedTwice = true;
9416                 var s = this;
9417                 setTimeout( function() {
9418                     s.tapedTwice = false;
9419                 }, 300 );
9420                 return;
9421             }
9422             event.preventDefault();
9423             var revent = new MouseEvent('dblclick',  {
9424                 view: window,
9425                 bubbles: true,
9426                 cancelable: true
9427             });
9428              
9429             this.dom.dispatchEvent(revent);
9430             //action on double tap goes below
9431              
9432         }, 
9433  
9434         /**
9435          * Removes an event handler from this element
9436          * @param {String} eventName the type of event to remove
9437          * @param {Function} fn the method the event invokes
9438          * @param {Function} scope (needed for svg fake listeners)
9439          * @return {Roo.Element} this
9440          */
9441         removeListener : function(eventName, fn, scope){
9442             Roo.EventManager.removeListener(this.dom,  eventName, fn);
9443             if (typeof(this.listeners) == 'undefined'  || typeof(this.listeners[eventName]) == 'undefined') {
9444                 return this;
9445             }
9446             this.listeners[eventName].removeListener(fn, scope);
9447             return this;
9448         },
9449
9450         /**
9451          * Removes all previous added listeners from this element
9452          * @return {Roo.Element} this
9453          */
9454         removeAllListeners : function(){
9455             E.purgeElement(this.dom);
9456             this.listeners = {};
9457             return this;
9458         },
9459
9460         relayEvent : function(eventName, observable){
9461             this.on(eventName, function(e){
9462                 observable.fireEvent(eventName, e);
9463             });
9464         },
9465
9466         
9467         /**
9468          * Set the opacity of the element
9469          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
9470          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9471          * @return {Roo.Element} this
9472          */
9473          setOpacity : function(opacity, animate){
9474             if(!animate || !A){
9475                 var s = this.dom.style;
9476                 if(Roo.isIE){
9477                     s.zoom = 1;
9478                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
9479                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
9480                 }else{
9481                     s.opacity = opacity;
9482                 }
9483             }else{
9484                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
9485             }
9486             return this;
9487         },
9488
9489         /**
9490          * Gets the left X coordinate
9491          * @param {Boolean} local True to get the local css position instead of page coordinate
9492          * @return {Number}
9493          */
9494         getLeft : function(local){
9495             if(!local){
9496                 return this.getX();
9497             }else{
9498                 return parseInt(this.getStyle("left"), 10) || 0;
9499             }
9500         },
9501
9502         /**
9503          * Gets the right X coordinate of the element (element X position + element width)
9504          * @param {Boolean} local True to get the local css position instead of page coordinate
9505          * @return {Number}
9506          */
9507         getRight : function(local){
9508             if(!local){
9509                 return this.getX() + this.getWidth();
9510             }else{
9511                 return (this.getLeft(true) + this.getWidth()) || 0;
9512             }
9513         },
9514
9515         /**
9516          * Gets the top Y coordinate
9517          * @param {Boolean} local True to get the local css position instead of page coordinate
9518          * @return {Number}
9519          */
9520         getTop : function(local) {
9521             if(!local){
9522                 return this.getY();
9523             }else{
9524                 return parseInt(this.getStyle("top"), 10) || 0;
9525             }
9526         },
9527
9528         /**
9529          * Gets the bottom Y coordinate of the element (element Y position + element height)
9530          * @param {Boolean} local True to get the local css position instead of page coordinate
9531          * @return {Number}
9532          */
9533         getBottom : function(local){
9534             if(!local){
9535                 return this.getY() + this.getHeight();
9536             }else{
9537                 return (this.getTop(true) + this.getHeight()) || 0;
9538             }
9539         },
9540
9541         /**
9542         * Initializes positioning on this element. If a desired position is not passed, it will make the
9543         * the element positioned relative IF it is not already positioned.
9544         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
9545         * @param {Number} zIndex (optional) The zIndex to apply
9546         * @param {Number} x (optional) Set the page X position
9547         * @param {Number} y (optional) Set the page Y position
9548         */
9549         position : function(pos, zIndex, x, y){
9550             if(!pos){
9551                if(this.getStyle('position') == 'static'){
9552                    this.setStyle('position', 'relative');
9553                }
9554             }else{
9555                 this.setStyle("position", pos);
9556             }
9557             if(zIndex){
9558                 this.setStyle("z-index", zIndex);
9559             }
9560             if(x !== undefined && y !== undefined){
9561                 this.setXY([x, y]);
9562             }else if(x !== undefined){
9563                 this.setX(x);
9564             }else if(y !== undefined){
9565                 this.setY(y);
9566             }
9567         },
9568
9569         /**
9570         * Clear positioning back to the default when the document was loaded
9571         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
9572         * @return {Roo.Element} this
9573          */
9574         clearPositioning : function(value){
9575             value = value ||'';
9576             this.setStyle({
9577                 "left": value,
9578                 "right": value,
9579                 "top": value,
9580                 "bottom": value,
9581                 "z-index": "",
9582                 "position" : "static"
9583             });
9584             return this;
9585         },
9586
9587         /**
9588         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
9589         * snapshot before performing an update and then restoring the element.
9590         * @return {Object}
9591         */
9592         getPositioning : function(){
9593             var l = this.getStyle("left");
9594             var t = this.getStyle("top");
9595             return {
9596                 "position" : this.getStyle("position"),
9597                 "left" : l,
9598                 "right" : l ? "" : this.getStyle("right"),
9599                 "top" : t,
9600                 "bottom" : t ? "" : this.getStyle("bottom"),
9601                 "z-index" : this.getStyle("z-index")
9602             };
9603         },
9604
9605         /**
9606          * Gets the width of the border(s) for the specified side(s)
9607          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
9608          * passing lr would get the border (l)eft width + the border (r)ight width.
9609          * @return {Number} The width of the sides passed added together
9610          */
9611         getBorderWidth : function(side){
9612             return this.addStyles(side, El.borders);
9613         },
9614
9615         /**
9616          * Gets the width of the padding(s) for the specified side(s)
9617          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
9618          * passing lr would get the padding (l)eft + the padding (r)ight.
9619          * @return {Number} The padding of the sides passed added together
9620          */
9621         getPadding : function(side){
9622             return this.addStyles(side, El.paddings);
9623         },
9624
9625         /**
9626         * Set positioning with an object returned by getPositioning().
9627         * @param {Object} posCfg
9628         * @return {Roo.Element} this
9629          */
9630         setPositioning : function(pc){
9631             this.applyStyles(pc);
9632             if(pc.right == "auto"){
9633                 this.dom.style.right = "";
9634             }
9635             if(pc.bottom == "auto"){
9636                 this.dom.style.bottom = "";
9637             }
9638             return this;
9639         },
9640
9641         // private
9642         fixDisplay : function(){
9643             if(this.getStyle("display") == "none"){
9644                 this.setStyle("visibility", "hidden");
9645                 this.setStyle("display", this.originalDisplay); // first try reverting to default
9646                 if(this.getStyle("display") == "none"){ // if that fails, default to block
9647                     this.setStyle("display", "block");
9648                 }
9649             }
9650         },
9651
9652         /**
9653          * Quick set left and top adding default units
9654          * @param {String} left The left CSS property value
9655          * @param {String} top The top CSS property value
9656          * @return {Roo.Element} this
9657          */
9658          setLeftTop : function(left, top){
9659             this.dom.style.left = this.addUnits(left);
9660             this.dom.style.top = this.addUnits(top);
9661             return this;
9662         },
9663
9664         /**
9665          * Move this element relative to its current position.
9666          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9667          * @param {Number} distance How far to move the element in pixels
9668          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9669          * @return {Roo.Element} this
9670          */
9671          move : function(direction, distance, animate){
9672             var xy = this.getXY();
9673             direction = direction.toLowerCase();
9674             switch(direction){
9675                 case "l":
9676                 case "left":
9677                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
9678                     break;
9679                case "r":
9680                case "right":
9681                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
9682                     break;
9683                case "t":
9684                case "top":
9685                case "up":
9686                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
9687                     break;
9688                case "b":
9689                case "bottom":
9690                case "down":
9691                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
9692                     break;
9693             }
9694             return this;
9695         },
9696
9697         /**
9698          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
9699          * @return {Roo.Element} this
9700          */
9701         clip : function(){
9702             if(!this.isClipped){
9703                this.isClipped = true;
9704                this.originalClip = {
9705                    "o": this.getStyle("overflow"),
9706                    "x": this.getStyle("overflow-x"),
9707                    "y": this.getStyle("overflow-y")
9708                };
9709                this.setStyle("overflow", "hidden");
9710                this.setStyle("overflow-x", "hidden");
9711                this.setStyle("overflow-y", "hidden");
9712             }
9713             return this;
9714         },
9715
9716         /**
9717          *  Return clipping (overflow) to original clipping before clip() was called
9718          * @return {Roo.Element} this
9719          */
9720         unclip : function(){
9721             if(this.isClipped){
9722                 this.isClipped = false;
9723                 var o = this.originalClip;
9724                 if(o.o){this.setStyle("overflow", o.o);}
9725                 if(o.x){this.setStyle("overflow-x", o.x);}
9726                 if(o.y){this.setStyle("overflow-y", o.y);}
9727             }
9728             return this;
9729         },
9730
9731
9732         /**
9733          * Gets the x,y coordinates specified by the anchor position on the element.
9734          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
9735          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
9736          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
9737          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
9738          * @return {Array} [x, y] An array containing the element's x and y coordinates
9739          */
9740         getAnchorXY : function(anchor, local, s){
9741             //Passing a different size is useful for pre-calculating anchors,
9742             //especially for anchored animations that change the el size.
9743
9744             var w, h, vp = false;
9745             if(!s){
9746                 var d = this.dom;
9747                 if(d == document.body || d == document){
9748                     vp = true;
9749                     w = D.getViewWidth(); h = D.getViewHeight();
9750                 }else{
9751                     w = this.getWidth(); h = this.getHeight();
9752                 }
9753             }else{
9754                 w = s.width;  h = s.height;
9755             }
9756             var x = 0, y = 0, r = Math.round;
9757             switch((anchor || "tl").toLowerCase()){
9758                 case "c":
9759                     x = r(w*.5);
9760                     y = r(h*.5);
9761                 break;
9762                 case "t":
9763                     x = r(w*.5);
9764                     y = 0;
9765                 break;
9766                 case "l":
9767                     x = 0;
9768                     y = r(h*.5);
9769                 break;
9770                 case "r":
9771                     x = w;
9772                     y = r(h*.5);
9773                 break;
9774                 case "b":
9775                     x = r(w*.5);
9776                     y = h;
9777                 break;
9778                 case "tl":
9779                     x = 0;
9780                     y = 0;
9781                 break;
9782                 case "bl":
9783                     x = 0;
9784                     y = h;
9785                 break;
9786                 case "br":
9787                     x = w;
9788                     y = h;
9789                 break;
9790                 case "tr":
9791                     x = w;
9792                     y = 0;
9793                 break;
9794             }
9795             if(local === true){
9796                 return [x, y];
9797             }
9798             if(vp){
9799                 var sc = this.getScroll();
9800                 return [x + sc.left, y + sc.top];
9801             }
9802             //Add the element's offset xy
9803             var o = this.getXY();
9804             return [x+o[0], y+o[1]];
9805         },
9806
9807         /**
9808          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
9809          * supported position values.
9810          * @param {String/HTMLElement/Roo.Element} element The element to align to.
9811          * @param {String} position The position to align to.
9812          * @param {Array} offsets (optional) Offset the positioning by [x, y]
9813          * @return {Array} [x, y]
9814          */
9815         getAlignToXY : function(el, p, o)
9816         {
9817             el = Roo.get(el);
9818             var d = this.dom;
9819             if(!el.dom){
9820                 throw "Element.alignTo with an element that doesn't exist";
9821             }
9822             var c = false; //constrain to viewport
9823             var p1 = "", p2 = "";
9824             o = o || [0,0];
9825
9826             if(!p){
9827                 p = "tl-bl";
9828             }else if(p == "?"){
9829                 p = "tl-bl?";
9830             }else if(p.indexOf("-") == -1){
9831                 p = "tl-" + p;
9832             }
9833             p = p.toLowerCase();
9834             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
9835             if(!m){
9836                throw "Element.alignTo with an invalid alignment " + p;
9837             }
9838             p1 = m[1]; p2 = m[2]; c = !!m[3];
9839
9840             //Subtract the aligned el's internal xy from the target's offset xy
9841             //plus custom offset to get the aligned el's new offset xy
9842             var a1 = this.getAnchorXY(p1, true);
9843             var a2 = el.getAnchorXY(p2, false);
9844             var x = a2[0] - a1[0] + o[0];
9845             var y = a2[1] - a1[1] + o[1];
9846             if(c){
9847                 //constrain the aligned el to viewport if necessary
9848                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
9849                 // 5px of margin for ie
9850                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
9851
9852                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
9853                 //perpendicular to the vp border, allow the aligned el to slide on that border,
9854                 //otherwise swap the aligned el to the opposite border of the target.
9855                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
9856                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
9857                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t")  );
9858                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
9859
9860                var doc = document;
9861                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
9862                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
9863
9864                if((x+w) > dw + scrollX){
9865                     x = swapX ? r.left-w : dw+scrollX-w;
9866                 }
9867                if(x < scrollX){
9868                    x = swapX ? r.right : scrollX;
9869                }
9870                if((y+h) > dh + scrollY){
9871                     y = swapY ? r.top-h : dh+scrollY-h;
9872                 }
9873                if (y < scrollY){
9874                    y = swapY ? r.bottom : scrollY;
9875                }
9876             }
9877             return [x,y];
9878         },
9879
9880         // private
9881         getConstrainToXY : function(){
9882             var os = {top:0, left:0, bottom:0, right: 0};
9883
9884             return function(el, local, offsets, proposedXY){
9885                 el = Roo.get(el);
9886                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
9887
9888                 var vw, vh, vx = 0, vy = 0;
9889                 if(el.dom == document.body || el.dom == document){
9890                     vw = Roo.lib.Dom.getViewWidth();
9891                     vh = Roo.lib.Dom.getViewHeight();
9892                 }else{
9893                     vw = el.dom.clientWidth;
9894                     vh = el.dom.clientHeight;
9895                     if(!local){
9896                         var vxy = el.getXY();
9897                         vx = vxy[0];
9898                         vy = vxy[1];
9899                     }
9900                 }
9901
9902                 var s = el.getScroll();
9903
9904                 vx += offsets.left + s.left;
9905                 vy += offsets.top + s.top;
9906
9907                 vw -= offsets.right;
9908                 vh -= offsets.bottom;
9909
9910                 var vr = vx+vw;
9911                 var vb = vy+vh;
9912
9913                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
9914                 var x = xy[0], y = xy[1];
9915                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
9916
9917                 // only move it if it needs it
9918                 var moved = false;
9919
9920                 // first validate right/bottom
9921                 if((x + w) > vr){
9922                     x = vr - w;
9923                     moved = true;
9924                 }
9925                 if((y + h) > vb){
9926                     y = vb - h;
9927                     moved = true;
9928                 }
9929                 // then make sure top/left isn't negative
9930                 if(x < vx){
9931                     x = vx;
9932                     moved = true;
9933                 }
9934                 if(y < vy){
9935                     y = vy;
9936                     moved = true;
9937                 }
9938                 return moved ? [x, y] : false;
9939             };
9940         }(),
9941
9942         // private
9943         adjustForConstraints : function(xy, parent, offsets){
9944             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
9945         },
9946
9947         /**
9948          * Aligns this element with another element relative to the specified anchor points. If the other element is the
9949          * document it aligns it to the viewport.
9950          * The position parameter is optional, and can be specified in any one of the following formats:
9951          * <ul>
9952          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
9953          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
9954          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
9955          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
9956          *   <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
9957          *       element's anchor point, and the second value is used as the target's anchor point.</li>
9958          * </ul>
9959          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
9960          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
9961          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
9962          * that specified in order to enforce the viewport constraints.
9963          * Following are all of the supported anchor positions:
9964     <pre>
9965     Value  Description
9966     -----  -----------------------------
9967     tl     The top left corner (default)
9968     t      The center of the top edge
9969     tr     The top right corner
9970     l      The center of the left edge
9971     c      In the center of the element
9972     r      The center of the right edge
9973     bl     The bottom left corner
9974     b      The center of the bottom edge
9975     br     The bottom right corner
9976     </pre>
9977     Example Usage:
9978     <pre><code>
9979     // align el to other-el using the default positioning ("tl-bl", non-constrained)
9980     el.alignTo("other-el");
9981
9982     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
9983     el.alignTo("other-el", "tr?");
9984
9985     // align the bottom right corner of el with the center left edge of other-el
9986     el.alignTo("other-el", "br-l?");
9987
9988     // align the center of el with the bottom left corner of other-el and
9989     // adjust the x position by -6 pixels (and the y position by 0)
9990     el.alignTo("other-el", "c-bl", [-6, 0]);
9991     </code></pre>
9992          * @param {String/HTMLElement/Roo.Element} element The element to align to.
9993          * @param {String} position The position to align to.
9994          * @param {Array} offsets (optional) Offset the positioning by [x, y]
9995          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9996          * @return {Roo.Element} this
9997          */
9998         alignTo : function(element, position, offsets, animate){
9999             var xy = this.getAlignToXY(element, position, offsets);
10000             this.setXY(xy, this.preanim(arguments, 3));
10001             return this;
10002         },
10003
10004         /**
10005          * Anchors an element to another element and realigns it when the window is resized.
10006          * @param {String/HTMLElement/Roo.Element} element The element to align to.
10007          * @param {String} position The position to align to.
10008          * @param {Array} offsets (optional) Offset the positioning by [x, y]
10009          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
10010          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
10011          * is a number, it is used as the buffer delay (defaults to 50ms).
10012          * @param {Function} callback The function to call after the animation finishes
10013          * @return {Roo.Element} this
10014          */
10015         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
10016             var action = function(){
10017                 this.alignTo(el, alignment, offsets, animate);
10018                 Roo.callback(callback, this);
10019             };
10020             Roo.EventManager.onWindowResize(action, this);
10021             var tm = typeof monitorScroll;
10022             if(tm != 'undefined'){
10023                 Roo.EventManager.on(window, 'scroll', action, this,
10024                     {buffer: tm == 'number' ? monitorScroll : 50});
10025             }
10026             action.call(this); // align immediately
10027             return this;
10028         },
10029         /**
10030          * Clears any opacity settings from this element. Required in some cases for IE.
10031          * @return {Roo.Element} this
10032          */
10033         clearOpacity : function(){
10034             if (window.ActiveXObject) {
10035                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
10036                     this.dom.style.filter = "";
10037                 }
10038             } else {
10039                 this.dom.style.opacity = "";
10040                 this.dom.style["-moz-opacity"] = "";
10041                 this.dom.style["-khtml-opacity"] = "";
10042             }
10043             return this;
10044         },
10045
10046         /**
10047          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
10048          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10049          * @return {Roo.Element} this
10050          */
10051         hide : function(animate){
10052             this.setVisible(false, this.preanim(arguments, 0));
10053             return this;
10054         },
10055
10056         /**
10057         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
10058         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10059          * @return {Roo.Element} this
10060          */
10061         show : function(animate){
10062             this.setVisible(true, this.preanim(arguments, 0));
10063             return this;
10064         },
10065
10066         /**
10067          * @private Test if size has a unit, otherwise appends the default
10068          */
10069         addUnits : function(size){
10070             return Roo.Element.addUnits(size, this.defaultUnit);
10071         },
10072
10073         /**
10074          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
10075          * @return {Roo.Element} this
10076          */
10077         beginMeasure : function(){
10078             var el = this.dom;
10079             if(el.offsetWidth || el.offsetHeight){
10080                 return this; // offsets work already
10081             }
10082             var changed = [];
10083             var p = this.dom, b = document.body; // start with this element
10084             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
10085                 var pe = Roo.get(p);
10086                 if(pe.getStyle('display') == 'none'){
10087                     changed.push({el: p, visibility: pe.getStyle("visibility")});
10088                     p.style.visibility = "hidden";
10089                     p.style.display = "block";
10090                 }
10091                 p = p.parentNode;
10092             }
10093             this._measureChanged = changed;
10094             return this;
10095
10096         },
10097
10098         /**
10099          * Restores displays to before beginMeasure was called
10100          * @return {Roo.Element} this
10101          */
10102         endMeasure : function(){
10103             var changed = this._measureChanged;
10104             if(changed){
10105                 for(var i = 0, len = changed.length; i < len; i++) {
10106                     var r = changed[i];
10107                     r.el.style.visibility = r.visibility;
10108                     r.el.style.display = "none";
10109                 }
10110                 this._measureChanged = null;
10111             }
10112             return this;
10113         },
10114
10115         /**
10116         * Update the innerHTML of this element, optionally searching for and processing scripts
10117         * @param {String} html The new HTML
10118         * @param {Boolean} loadScripts (optional) true to look for and process scripts
10119         * @param {Function} callback For async script loading you can be noticed when the update completes
10120         * @return {Roo.Element} this
10121          */
10122         update : function(html, loadScripts, callback){
10123             if(typeof html == "undefined"){
10124                 html = "";
10125             }
10126             if(loadScripts !== true){
10127                 this.dom.innerHTML = html;
10128                 if(typeof callback == "function"){
10129                     callback();
10130                 }
10131                 return this;
10132             }
10133             var id = Roo.id();
10134             var dom = this.dom;
10135
10136             html += '<span id="' + id + '"></span>';
10137
10138             E.onAvailable(id, function(){
10139                 var hd = document.getElementsByTagName("head")[0];
10140                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
10141                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
10142                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
10143
10144                 var match;
10145                 while(match = re.exec(html)){
10146                     var attrs = match[1];
10147                     var srcMatch = attrs ? attrs.match(srcRe) : false;
10148                     if(srcMatch && srcMatch[2]){
10149                        var s = document.createElement("script");
10150                        s.src = srcMatch[2];
10151                        var typeMatch = attrs.match(typeRe);
10152                        if(typeMatch && typeMatch[2]){
10153                            s.type = typeMatch[2];
10154                        }
10155                        hd.appendChild(s);
10156                     }else if(match[2] && match[2].length > 0){
10157                         if(window.execScript) {
10158                            window.execScript(match[2]);
10159                         } else {
10160                             /**
10161                              * eval:var:id
10162                              * eval:var:dom
10163                              * eval:var:html
10164                              * 
10165                              */
10166                            window.eval(match[2]);
10167                         }
10168                     }
10169                 }
10170                 var el = document.getElementById(id);
10171                 if(el){el.parentNode.removeChild(el);}
10172                 if(typeof callback == "function"){
10173                     callback();
10174                 }
10175             });
10176             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
10177             return this;
10178         },
10179
10180         /**
10181          * Direct access to the UpdateManager update() method (takes the same parameters).
10182          * @param {String/Function} url The url for this request or a function to call to get the url
10183          * @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}
10184          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
10185          * @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.
10186          * @return {Roo.Element} this
10187          */
10188         load : function(){
10189             var um = this.getUpdateManager();
10190             um.update.apply(um, arguments);
10191             return this;
10192         },
10193
10194         /**
10195         * Gets this element's UpdateManager
10196         * @return {Roo.UpdateManager} The UpdateManager
10197         */
10198         getUpdateManager : function(){
10199             if(!this.updateManager){
10200                 this.updateManager = new Roo.UpdateManager(this);
10201             }
10202             return this.updateManager;
10203         },
10204
10205         /**
10206          * Disables text selection for this element (normalized across browsers)
10207          * @return {Roo.Element} this
10208          */
10209         unselectable : function(){
10210             this.dom.unselectable = "on";
10211             this.swallowEvent("selectstart", true);
10212             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
10213             this.addClass("x-unselectable");
10214             return this;
10215         },
10216
10217         /**
10218         * Calculates the x, y to center this element on the screen
10219         * @return {Array} The x, y values [x, y]
10220         */
10221         getCenterXY : function(){
10222             return this.getAlignToXY(document, 'c-c');
10223         },
10224
10225         /**
10226         * Centers the Element in either the viewport, or another Element.
10227         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
10228         */
10229         center : function(centerIn){
10230             this.alignTo(centerIn || document, 'c-c');
10231             return this;
10232         },
10233
10234         /**
10235          * Tests various css rules/browsers to determine if this element uses a border box
10236          * @return {Boolean}
10237          */
10238         isBorderBox : function(){
10239             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
10240         },
10241
10242         /**
10243          * Return a box {x, y, width, height} that can be used to set another elements
10244          * size/location to match this element.
10245          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
10246          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
10247          * @return {Object} box An object in the format {x, y, width, height}
10248          */
10249         getBox : function(contentBox, local){
10250             var xy;
10251             if(!local){
10252                 xy = this.getXY();
10253             }else{
10254                 var left = parseInt(this.getStyle("left"), 10) || 0;
10255                 var top = parseInt(this.getStyle("top"), 10) || 0;
10256                 xy = [left, top];
10257             }
10258             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
10259             if(!contentBox){
10260                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
10261             }else{
10262                 var l = this.getBorderWidth("l")+this.getPadding("l");
10263                 var r = this.getBorderWidth("r")+this.getPadding("r");
10264                 var t = this.getBorderWidth("t")+this.getPadding("t");
10265                 var b = this.getBorderWidth("b")+this.getPadding("b");
10266                 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)};
10267             }
10268             bx.right = bx.x + bx.width;
10269             bx.bottom = bx.y + bx.height;
10270             return bx;
10271         },
10272
10273         /**
10274          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
10275          for more information about the sides.
10276          * @param {String} sides
10277          * @return {Number}
10278          */
10279         getFrameWidth : function(sides, onlyContentBox){
10280             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
10281         },
10282
10283         /**
10284          * 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.
10285          * @param {Object} box The box to fill {x, y, width, height}
10286          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
10287          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10288          * @return {Roo.Element} this
10289          */
10290         setBox : function(box, adjust, animate){
10291             var w = box.width, h = box.height;
10292             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
10293                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
10294                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
10295             }
10296             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
10297             return this;
10298         },
10299
10300         /**
10301          * Forces the browser to repaint this element
10302          * @return {Roo.Element} this
10303          */
10304          repaint : function(){
10305             var dom = this.dom;
10306             this.addClass("x-repaint");
10307             setTimeout(function(){
10308                 Roo.get(dom).removeClass("x-repaint");
10309             }, 1);
10310             return this;
10311         },
10312
10313         /**
10314          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
10315          * then it returns the calculated width of the sides (see getPadding)
10316          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
10317          * @return {Object/Number}
10318          */
10319         getMargins : function(side){
10320             if(!side){
10321                 return {
10322                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
10323                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
10324                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
10325                     right: parseInt(this.getStyle("margin-right"), 10) || 0
10326                 };
10327             }else{
10328                 return this.addStyles(side, El.margins);
10329              }
10330         },
10331
10332         // private
10333         addStyles : function(sides, styles){
10334             var val = 0, v, w;
10335             for(var i = 0, len = sides.length; i < len; i++){
10336                 v = this.getStyle(styles[sides.charAt(i)]);
10337                 if(v){
10338                      w = parseInt(v, 10);
10339                      if(w){ val += w; }
10340                 }
10341             }
10342             return val;
10343         },
10344
10345         /**
10346          * Creates a proxy element of this element
10347          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
10348          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
10349          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
10350          * @return {Roo.Element} The new proxy element
10351          */
10352         createProxy : function(config, renderTo, matchBox){
10353             if(renderTo){
10354                 renderTo = Roo.getDom(renderTo);
10355             }else{
10356                 renderTo = document.body;
10357             }
10358             config = typeof config == "object" ?
10359                 config : {tag : "div", cls: config};
10360             var proxy = Roo.DomHelper.append(renderTo, config, true);
10361             if(matchBox){
10362                proxy.setBox(this.getBox());
10363             }
10364             return proxy;
10365         },
10366
10367         /**
10368          * Puts a mask over this element to disable user interaction. Requires core.css.
10369          * This method can only be applied to elements which accept child nodes.
10370          * @param {String} msg (optional) A message to display in the mask
10371          * @param {String} msgCls (optional) A css class to apply to the msg element - use no-spinner to hide the spinner on bootstrap
10372          * @return {Element} The mask  element
10373          */
10374         mask : function(msg, msgCls)
10375         {
10376             if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
10377                 this.setStyle("position", "relative");
10378             }
10379             if(!this._mask){
10380                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
10381             }
10382             
10383             this.addClass("x-masked");
10384             this._mask.setDisplayed(true);
10385             
10386             // we wander
10387             var z = 0;
10388             var dom = this.dom;
10389             while (dom && dom.style) {
10390                 if (!isNaN(parseInt(dom.style.zIndex))) {
10391                     z = Math.max(z, parseInt(dom.style.zIndex));
10392                 }
10393                 dom = dom.parentNode;
10394             }
10395             // if we are masking the body - then it hides everything..
10396             if (this.dom == document.body) {
10397                 z = 1000000;
10398                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
10399                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
10400             }
10401            
10402             if(typeof msg == 'string'){
10403                 if(!this._maskMsg){
10404                     this._maskMsg = Roo.DomHelper.append(this.dom, {
10405                         cls: "roo-el-mask-msg", 
10406                         cn: [
10407                             {
10408                                 tag: 'i',
10409                                 cls: 'fa fa-spinner fa-spin'
10410                             },
10411                             {
10412                                 tag: 'div'
10413                             }   
10414                         ]
10415                     }, true);
10416                 }
10417                 var mm = this._maskMsg;
10418                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
10419                 if (mm.dom.lastChild) { // weird IE issue?
10420                     mm.dom.lastChild.innerHTML = msg;
10421                 }
10422                 mm.setDisplayed(true);
10423                 mm.center(this);
10424                 mm.setStyle('z-index', z + 102);
10425             }
10426             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
10427                 this._mask.setHeight(this.getHeight());
10428             }
10429             this._mask.setStyle('z-index', z + 100);
10430             
10431             return this._mask;
10432         },
10433
10434         /**
10435          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
10436          * it is cached for reuse.
10437          */
10438         unmask : function(removeEl){
10439             if(this._mask){
10440                 if(removeEl === true){
10441                     this._mask.remove();
10442                     delete this._mask;
10443                     if(this._maskMsg){
10444                         this._maskMsg.remove();
10445                         delete this._maskMsg;
10446                     }
10447                 }else{
10448                     this._mask.setDisplayed(false);
10449                     if(this._maskMsg){
10450                         this._maskMsg.setDisplayed(false);
10451                     }
10452                 }
10453             }
10454             this.removeClass("x-masked");
10455         },
10456
10457         /**
10458          * Returns true if this element is masked
10459          * @return {Boolean}
10460          */
10461         isMasked : function(){
10462             return this._mask && this._mask.isVisible();
10463         },
10464
10465         /**
10466          * Creates an iframe shim for this element to keep selects and other windowed objects from
10467          * showing through.
10468          * @return {Roo.Element} The new shim element
10469          */
10470         createShim : function(){
10471             var el = document.createElement('iframe');
10472             el.frameBorder = 'no';
10473             el.className = 'roo-shim';
10474             if(Roo.isIE && Roo.isSecure){
10475                 el.src = Roo.SSL_SECURE_URL;
10476             }
10477             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
10478             shim.autoBoxAdjust = false;
10479             return shim;
10480         },
10481
10482         /**
10483          * Removes this element from the DOM and deletes it from the cache
10484          */
10485         remove : function(){
10486             if(this.dom.parentNode){
10487                 this.dom.parentNode.removeChild(this.dom);
10488             }
10489             delete El.cache[this.dom.id];
10490         },
10491
10492         /**
10493          * Sets up event handlers to add and remove a css class when the mouse is over this element
10494          * @param {String} className
10495          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
10496          * mouseout events for children elements
10497          * @return {Roo.Element} this
10498          */
10499         addClassOnOver : function(className, preventFlicker){
10500             this.on("mouseover", function(){
10501                 Roo.fly(this, '_internal').addClass(className);
10502             }, this.dom);
10503             var removeFn = function(e){
10504                 if(preventFlicker !== true || !e.within(this, true)){
10505                     Roo.fly(this, '_internal').removeClass(className);
10506                 }
10507             };
10508             this.on("mouseout", removeFn, this.dom);
10509             return this;
10510         },
10511
10512         /**
10513          * Sets up event handlers to add and remove a css class when this element has the focus
10514          * @param {String} className
10515          * @return {Roo.Element} this
10516          */
10517         addClassOnFocus : function(className){
10518             this.on("focus", function(){
10519                 Roo.fly(this, '_internal').addClass(className);
10520             }, this.dom);
10521             this.on("blur", function(){
10522                 Roo.fly(this, '_internal').removeClass(className);
10523             }, this.dom);
10524             return this;
10525         },
10526         /**
10527          * 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)
10528          * @param {String} className
10529          * @return {Roo.Element} this
10530          */
10531         addClassOnClick : function(className){
10532             var dom = this.dom;
10533             this.on("mousedown", function(){
10534                 Roo.fly(dom, '_internal').addClass(className);
10535                 var d = Roo.get(document);
10536                 var fn = function(){
10537                     Roo.fly(dom, '_internal').removeClass(className);
10538                     d.removeListener("mouseup", fn);
10539                 };
10540                 d.on("mouseup", fn);
10541             });
10542             return this;
10543         },
10544
10545         /**
10546          * Stops the specified event from bubbling and optionally prevents the default action
10547          * @param {String} eventName
10548          * @param {Boolean} preventDefault (optional) true to prevent the default action too
10549          * @return {Roo.Element} this
10550          */
10551         swallowEvent : function(eventName, preventDefault){
10552             var fn = function(e){
10553                 e.stopPropagation();
10554                 if(preventDefault){
10555                     e.preventDefault();
10556                 }
10557             };
10558             if(eventName instanceof Array){
10559                 for(var i = 0, len = eventName.length; i < len; i++){
10560                      this.on(eventName[i], fn);
10561                 }
10562                 return this;
10563             }
10564             this.on(eventName, fn);
10565             return this;
10566         },
10567
10568         /**
10569          * @private
10570          */
10571         fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
10572
10573         /**
10574          * Sizes this element to its parent element's dimensions performing
10575          * neccessary box adjustments.
10576          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
10577          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
10578          * @return {Roo.Element} this
10579          */
10580         fitToParent : function(monitorResize, targetParent) {
10581           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
10582           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
10583           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
10584             return this;
10585           }
10586           var p = Roo.get(targetParent || this.dom.parentNode);
10587           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
10588           if (monitorResize === true) {
10589             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
10590             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
10591           }
10592           return this;
10593         },
10594
10595         /**
10596          * Gets the next sibling, skipping text nodes
10597          * @return {HTMLElement} The next sibling or null
10598          */
10599         getNextSibling : function(){
10600             var n = this.dom.nextSibling;
10601             while(n && n.nodeType != 1){
10602                 n = n.nextSibling;
10603             }
10604             return n;
10605         },
10606
10607         /**
10608          * Gets the previous sibling, skipping text nodes
10609          * @return {HTMLElement} The previous sibling or null
10610          */
10611         getPrevSibling : function(){
10612             var n = this.dom.previousSibling;
10613             while(n && n.nodeType != 1){
10614                 n = n.previousSibling;
10615             }
10616             return n;
10617         },
10618
10619
10620         /**
10621          * Appends the passed element(s) to this element
10622          * @param {String/HTMLElement/Array/Element/CompositeElement} el
10623          * @return {Roo.Element} this
10624          */
10625         appendChild: function(el){
10626             el = Roo.get(el);
10627             el.appendTo(this);
10628             return this;
10629         },
10630
10631         /**
10632          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
10633          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
10634          * automatically generated with the specified attributes.
10635          * @param {HTMLElement} insertBefore (optional) a child element of this element
10636          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
10637          * @return {Roo.Element} The new child element
10638          */
10639         createChild: function(config, insertBefore, returnDom){
10640             config = config || {tag:'div'};
10641             if(insertBefore){
10642                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
10643             }
10644             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
10645         },
10646
10647         /**
10648          * Appends this element to the passed element
10649          * @param {String/HTMLElement/Element} el The new parent element
10650          * @return {Roo.Element} this
10651          */
10652         appendTo: function(el){
10653             el = Roo.getDom(el);
10654             el.appendChild(this.dom);
10655             return this;
10656         },
10657
10658         /**
10659          * Inserts this element before the passed element in the DOM
10660          * @param {String/HTMLElement/Element} el The element to insert before
10661          * @return {Roo.Element} this
10662          */
10663         insertBefore: function(el){
10664             el = Roo.getDom(el);
10665             el.parentNode.insertBefore(this.dom, el);
10666             return this;
10667         },
10668
10669         /**
10670          * Inserts this element after the passed element in the DOM
10671          * @param {String/HTMLElement/Element} el The element to insert after
10672          * @return {Roo.Element} this
10673          */
10674         insertAfter: function(el){
10675             el = Roo.getDom(el);
10676             el.parentNode.insertBefore(this.dom, el.nextSibling);
10677             return this;
10678         },
10679
10680         /**
10681          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
10682          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
10683          * @return {Roo.Element} The new child
10684          */
10685         insertFirst: function(el, returnDom){
10686             el = el || {};
10687             if(typeof el == 'object' && !el.nodeType){ // dh config
10688                 return this.createChild(el, this.dom.firstChild, returnDom);
10689             }else{
10690                 el = Roo.getDom(el);
10691                 this.dom.insertBefore(el, this.dom.firstChild);
10692                 return !returnDom ? Roo.get(el) : el;
10693             }
10694         },
10695
10696         /**
10697          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
10698          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
10699          * @param {String} where (optional) 'before' or 'after' defaults to before
10700          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
10701          * @return {Roo.Element} the inserted Element
10702          */
10703         insertSibling: function(el, where, returnDom){
10704             where = where ? where.toLowerCase() : 'before';
10705             el = el || {};
10706             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
10707
10708             if(typeof el == 'object' && !el.nodeType){ // dh config
10709                 if(where == 'after' && !this.dom.nextSibling){
10710                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
10711                 }else{
10712                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
10713                 }
10714
10715             }else{
10716                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
10717                             where == 'before' ? this.dom : this.dom.nextSibling);
10718                 if(!returnDom){
10719                     rt = Roo.get(rt);
10720                 }
10721             }
10722             return rt;
10723         },
10724
10725         /**
10726          * Creates and wraps this element with another element
10727          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
10728          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
10729          * @return {HTMLElement/Element} The newly created wrapper element
10730          */
10731         wrap: function(config, returnDom){
10732             if(!config){
10733                 config = {tag: "div"};
10734             }
10735             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
10736             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
10737             return newEl;
10738         },
10739
10740         /**
10741          * Replaces the passed element with this element
10742          * @param {String/HTMLElement/Element} el The element to replace
10743          * @return {Roo.Element} this
10744          */
10745         replace: function(el){
10746             el = Roo.get(el);
10747             this.insertBefore(el);
10748             el.remove();
10749             return this;
10750         },
10751
10752         /**
10753          * Inserts an html fragment into this element
10754          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
10755          * @param {String} html The HTML fragment
10756          * @param {Boolean} returnEl True to return an Roo.Element
10757          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
10758          */
10759         insertHtml : function(where, html, returnEl){
10760             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
10761             return returnEl ? Roo.get(el) : el;
10762         },
10763
10764         /**
10765          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
10766          * @param {Object} o The object with the attributes
10767          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
10768          * @return {Roo.Element} this
10769          */
10770         set : function(o, useSet){
10771             var el = this.dom;
10772             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
10773             for(var attr in o){
10774                 if(attr == "style" || typeof o[attr] == "function")  { continue; }
10775                 if(attr=="cls"){
10776                     el.className = o["cls"];
10777                 }else{
10778                     if(useSet) {
10779                         el.setAttribute(attr, o[attr]);
10780                     } else {
10781                         el[attr] = o[attr];
10782                     }
10783                 }
10784             }
10785             if(o.style){
10786                 Roo.DomHelper.applyStyles(el, o.style);
10787             }
10788             return this;
10789         },
10790
10791         /**
10792          * Convenience method for constructing a KeyMap
10793          * @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:
10794          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
10795          * @param {Function} fn The function to call
10796          * @param {Object} scope (optional) The scope of the function
10797          * @return {Roo.KeyMap} The KeyMap created
10798          */
10799         addKeyListener : function(key, fn, scope){
10800             var config;
10801             if(typeof key != "object" || key instanceof Array){
10802                 config = {
10803                     key: key,
10804                     fn: fn,
10805                     scope: scope
10806                 };
10807             }else{
10808                 config = {
10809                     key : key.key,
10810                     shift : key.shift,
10811                     ctrl : key.ctrl,
10812                     alt : key.alt,
10813                     fn: fn,
10814                     scope: scope
10815                 };
10816             }
10817             return new Roo.KeyMap(this, config);
10818         },
10819
10820         /**
10821          * Creates a KeyMap for this element
10822          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
10823          * @return {Roo.KeyMap} The KeyMap created
10824          */
10825         addKeyMap : function(config){
10826             return new Roo.KeyMap(this, config);
10827         },
10828
10829         /**
10830          * Returns true if this element is scrollable.
10831          * @return {Boolean}
10832          */
10833          isScrollable : function(){
10834             var dom = this.dom;
10835             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
10836         },
10837
10838         /**
10839          * 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().
10840          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
10841          * @param {Number} value The new scroll value
10842          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10843          * @return {Element} this
10844          */
10845
10846         scrollTo : function(side, value, animate){
10847             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
10848             if(!animate || !A){
10849                 this.dom[prop] = value;
10850             }else{
10851                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
10852                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
10853             }
10854             return this;
10855         },
10856
10857         /**
10858          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
10859          * within this element's scrollable range.
10860          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
10861          * @param {Number} distance How far to scroll the element in pixels
10862          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10863          * @return {Boolean} Returns true if a scroll was triggered or false if the element
10864          * was scrolled as far as it could go.
10865          */
10866          scroll : function(direction, distance, animate){
10867              if(!this.isScrollable()){
10868                  return;
10869              }
10870              var el = this.dom;
10871              var l = el.scrollLeft, t = el.scrollTop;
10872              var w = el.scrollWidth, h = el.scrollHeight;
10873              var cw = el.clientWidth, ch = el.clientHeight;
10874              direction = direction.toLowerCase();
10875              var scrolled = false;
10876              var a = this.preanim(arguments, 2);
10877              switch(direction){
10878                  case "l":
10879                  case "left":
10880                      if(w - l > cw){
10881                          var v = Math.min(l + distance, w-cw);
10882                          this.scrollTo("left", v, a);
10883                          scrolled = true;
10884                      }
10885                      break;
10886                 case "r":
10887                 case "right":
10888                      if(l > 0){
10889                          var v = Math.max(l - distance, 0);
10890                          this.scrollTo("left", v, a);
10891                          scrolled = true;
10892                      }
10893                      break;
10894                 case "t":
10895                 case "top":
10896                 case "up":
10897                      if(t > 0){
10898                          var v = Math.max(t - distance, 0);
10899                          this.scrollTo("top", v, a);
10900                          scrolled = true;
10901                      }
10902                      break;
10903                 case "b":
10904                 case "bottom":
10905                 case "down":
10906                      if(h - t > ch){
10907                          var v = Math.min(t + distance, h-ch);
10908                          this.scrollTo("top", v, a);
10909                          scrolled = true;
10910                      }
10911                      break;
10912              }
10913              return scrolled;
10914         },
10915
10916         /**
10917          * Translates the passed page coordinates into left/top css values for this element
10918          * @param {Number/Array} x The page x or an array containing [x, y]
10919          * @param {Number} y The page y
10920          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
10921          */
10922         translatePoints : function(x, y){
10923             if(typeof x == 'object' || x instanceof Array){
10924                 y = x[1]; x = x[0];
10925             }
10926             var p = this.getStyle('position');
10927             var o = this.getXY();
10928
10929             var l = parseInt(this.getStyle('left'), 10);
10930             var t = parseInt(this.getStyle('top'), 10);
10931
10932             if(isNaN(l)){
10933                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
10934             }
10935             if(isNaN(t)){
10936                 t = (p == "relative") ? 0 : this.dom.offsetTop;
10937             }
10938
10939             return {left: (x - o[0] + l), top: (y - o[1] + t)};
10940         },
10941
10942         /**
10943          * Returns the current scroll position of the element.
10944          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
10945          */
10946         getScroll : function(){
10947             var d = this.dom, doc = document;
10948             if(d == doc || d == doc.body){
10949                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
10950                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
10951                 return {left: l, top: t};
10952             }else{
10953                 return {left: d.scrollLeft, top: d.scrollTop};
10954             }
10955         },
10956
10957         /**
10958          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
10959          * are convert to standard 6 digit hex color.
10960          * @param {String} attr The css attribute
10961          * @param {String} defaultValue The default value to use when a valid color isn't found
10962          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
10963          * YUI color anims.
10964          */
10965         getColor : function(attr, defaultValue, prefix){
10966             var v = this.getStyle(attr);
10967             if(!v || v == "transparent" || v == "inherit") {
10968                 return defaultValue;
10969             }
10970             var color = typeof prefix == "undefined" ? "#" : prefix;
10971             if(v.substr(0, 4) == "rgb("){
10972                 var rvs = v.slice(4, v.length -1).split(",");
10973                 for(var i = 0; i < 3; i++){
10974                     var h = parseInt(rvs[i]).toString(16);
10975                     if(h < 16){
10976                         h = "0" + h;
10977                     }
10978                     color += h;
10979                 }
10980             } else {
10981                 if(v.substr(0, 1) == "#"){
10982                     if(v.length == 4) {
10983                         for(var i = 1; i < 4; i++){
10984                             var c = v.charAt(i);
10985                             color +=  c + c;
10986                         }
10987                     }else if(v.length == 7){
10988                         color += v.substr(1);
10989                     }
10990                 }
10991             }
10992             return(color.length > 5 ? color.toLowerCase() : defaultValue);
10993         },
10994
10995         /**
10996          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
10997          * gradient background, rounded corners and a 4-way shadow.
10998          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
10999          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
11000          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
11001          * @return {Roo.Element} this
11002          */
11003         boxWrap : function(cls){
11004             cls = cls || 'x-box';
11005             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
11006             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
11007             return el;
11008         },
11009
11010         /**
11011          * Returns the value of a namespaced attribute from the element's underlying DOM node.
11012          * @param {String} namespace The namespace in which to look for the attribute
11013          * @param {String} name The attribute name
11014          * @return {String} The attribute value
11015          */
11016         getAttributeNS : Roo.isIE ? function(ns, name){
11017             var d = this.dom;
11018             var type = typeof d[ns+":"+name];
11019             if(type != 'undefined' && type != 'unknown'){
11020                 return d[ns+":"+name];
11021             }
11022             return d[name];
11023         } : function(ns, name){
11024             var d = this.dom;
11025             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
11026         },
11027         
11028         
11029         /**
11030          * Sets or Returns the value the dom attribute value
11031          * @param {String|Object} name The attribute name (or object to set multiple attributes)
11032          * @param {String} value (optional) The value to set the attribute to
11033          * @return {String} The attribute value
11034          */
11035         attr : function(name){
11036             if (arguments.length > 1) {
11037                 this.dom.setAttribute(name, arguments[1]);
11038                 return arguments[1];
11039             }
11040             if (typeof(name) == 'object') {
11041                 for(var i in name) {
11042                     this.attr(i, name[i]);
11043                 }
11044                 return name;
11045             }
11046             
11047             
11048             if (!this.dom.hasAttribute(name)) {
11049                 return undefined;
11050             }
11051             return this.dom.getAttribute(name);
11052         }
11053         
11054         
11055         
11056     };
11057
11058     var ep = El.prototype;
11059
11060     /**
11061      * Appends an event handler (Shorthand for addListener)
11062      * @param {String}   eventName     The type of event to append
11063      * @param {Function} fn        The method the event invokes
11064      * @param {Object} scope       (optional) The scope (this object) of the fn
11065      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
11066      * @method
11067      */
11068     ep.on = ep.addListener;
11069         // backwards compat
11070     ep.mon = ep.addListener;
11071
11072     /**
11073      * Removes an event handler from this element (shorthand for removeListener)
11074      * @param {String} eventName the type of event to remove
11075      * @param {Function} fn the method the event invokes
11076      * @return {Roo.Element} this
11077      * @method
11078      */
11079     ep.un = ep.removeListener;
11080
11081     /**
11082      * true to automatically adjust width and height settings for box-model issues (default to true)
11083      */
11084     ep.autoBoxAdjust = true;
11085
11086     // private
11087     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
11088
11089     // private
11090     El.addUnits = function(v, defaultUnit){
11091         if(v === "" || v == "auto"){
11092             return v;
11093         }
11094         if(v === undefined){
11095             return '';
11096         }
11097         if(typeof v == "number" || !El.unitPattern.test(v)){
11098             return v + (defaultUnit || 'px');
11099         }
11100         return v;
11101     };
11102
11103     // special markup used throughout Roo when box wrapping elements
11104     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>';
11105     /**
11106      * Visibility mode constant - Use visibility to hide element
11107      * @static
11108      * @type Number
11109      */
11110     El.VISIBILITY = 1;
11111     /**
11112      * Visibility mode constant - Use display to hide element
11113      * @static
11114      * @type Number
11115      */
11116     El.DISPLAY = 2;
11117
11118     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
11119     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
11120     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
11121
11122
11123
11124     /**
11125      * @private
11126      */
11127     El.cache = {};
11128
11129     var docEl;
11130
11131     /**
11132      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
11133      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
11134      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
11135      * @return {Element} The Element object
11136      * @static
11137      */
11138     El.get = function(el){
11139         var ex, elm, id;
11140         if(!el){ return null; }
11141         if(typeof el == "string"){ // element id
11142             if(!(elm = document.getElementById(el))){
11143                 return null;
11144             }
11145             if(ex = El.cache[el]){
11146                 ex.dom = elm;
11147             }else{
11148                 ex = El.cache[el] = new El(elm);
11149             }
11150             return ex;
11151         }else if(el.tagName){ // dom element
11152             if(!(id = el.id)){
11153                 id = Roo.id(el);
11154             }
11155             if(ex = El.cache[id]){
11156                 ex.dom = el;
11157             }else{
11158                 ex = El.cache[id] = new El(el);
11159             }
11160             return ex;
11161         }else if(el instanceof El){
11162             if(el != docEl){
11163                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
11164                                                               // catch case where it hasn't been appended
11165                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
11166             }
11167             return el;
11168         }else if(el.isComposite){
11169             return el;
11170         }else if(el instanceof Array){
11171             return El.select(el);
11172         }else if(el == document){
11173             // create a bogus element object representing the document object
11174             if(!docEl){
11175                 var f = function(){};
11176                 f.prototype = El.prototype;
11177                 docEl = new f();
11178                 docEl.dom = document;
11179             }
11180             return docEl;
11181         }
11182         return null;
11183     };
11184
11185     // private
11186     El.uncache = function(el){
11187         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
11188             if(a[i]){
11189                 delete El.cache[a[i].id || a[i]];
11190             }
11191         }
11192     };
11193
11194     // private
11195     // Garbage collection - uncache elements/purge listeners on orphaned elements
11196     // so we don't hold a reference and cause the browser to retain them
11197     El.garbageCollect = function(){
11198         if(!Roo.enableGarbageCollector){
11199             clearInterval(El.collectorThread);
11200             return;
11201         }
11202         for(var eid in El.cache){
11203             var el = El.cache[eid], d = el.dom;
11204             // -------------------------------------------------------
11205             // Determining what is garbage:
11206             // -------------------------------------------------------
11207             // !d
11208             // dom node is null, definitely garbage
11209             // -------------------------------------------------------
11210             // !d.parentNode
11211             // no parentNode == direct orphan, definitely garbage
11212             // -------------------------------------------------------
11213             // !d.offsetParent && !document.getElementById(eid)
11214             // display none elements have no offsetParent so we will
11215             // also try to look it up by it's id. However, check
11216             // offsetParent first so we don't do unneeded lookups.
11217             // This enables collection of elements that are not orphans
11218             // directly, but somewhere up the line they have an orphan
11219             // parent.
11220             // -------------------------------------------------------
11221             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
11222                 delete El.cache[eid];
11223                 if(d && Roo.enableListenerCollection){
11224                     E.purgeElement(d);
11225                 }
11226             }
11227         }
11228     }
11229     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
11230
11231
11232     // dom is optional
11233     El.Flyweight = function(dom){
11234         this.dom = dom;
11235     };
11236     El.Flyweight.prototype = El.prototype;
11237
11238     El._flyweights = {};
11239     /**
11240      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
11241      * the dom node can be overwritten by other code.
11242      * @param {String/HTMLElement} el The dom node or id
11243      * @param {String} named (optional) Allows for creation of named reusable flyweights to
11244      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
11245      * @static
11246      * @return {Element} The shared Element object
11247      */
11248     El.fly = function(el, named){
11249         named = named || '_global';
11250         el = Roo.getDom(el);
11251         if(!el){
11252             return null;
11253         }
11254         if(!El._flyweights[named]){
11255             El._flyweights[named] = new El.Flyweight();
11256         }
11257         El._flyweights[named].dom = el;
11258         return El._flyweights[named];
11259     };
11260
11261     /**
11262      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
11263      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
11264      * Shorthand of {@link Roo.Element#get}
11265      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
11266      * @return {Element} The Element object
11267      * @member Roo
11268      * @method get
11269      */
11270     Roo.get = El.get;
11271     /**
11272      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
11273      * the dom node can be overwritten by other code.
11274      * Shorthand of {@link Roo.Element#fly}
11275      * @param {String/HTMLElement} el The dom node or id
11276      * @param {String} named (optional) Allows for creation of named reusable flyweights to
11277      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
11278      * @static
11279      * @return {Element} The shared Element object
11280      * @member Roo
11281      * @method fly
11282      */
11283     Roo.fly = El.fly;
11284
11285     // speedy lookup for elements never to box adjust
11286     var noBoxAdjust = Roo.isStrict ? {
11287         select:1
11288     } : {
11289         input:1, select:1, textarea:1
11290     };
11291     if(Roo.isIE || Roo.isGecko){
11292         noBoxAdjust['button'] = 1;
11293     }
11294
11295
11296     Roo.EventManager.on(window, 'unload', function(){
11297         delete El.cache;
11298         delete El._flyweights;
11299     });
11300 })();
11301
11302
11303
11304
11305 if(Roo.DomQuery){
11306     Roo.Element.selectorFunction = Roo.DomQuery.select;
11307 }
11308
11309 Roo.Element.select = function(selector, unique, root){
11310     var els;
11311     if(typeof selector == "string"){
11312         els = Roo.Element.selectorFunction(selector, root);
11313     }else if(selector.length !== undefined){
11314         els = selector;
11315     }else{
11316         throw "Invalid selector";
11317     }
11318     if(unique === true){
11319         return new Roo.CompositeElement(els);
11320     }else{
11321         return new Roo.CompositeElementLite(els);
11322     }
11323 };
11324 /**
11325  * Selects elements based on the passed CSS selector to enable working on them as 1.
11326  * @param {String/Array} selector The CSS selector or an array of elements
11327  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
11328  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
11329  * @return {CompositeElementLite/CompositeElement}
11330  * @member Roo
11331  * @method select
11332  */
11333 Roo.select = Roo.Element.select;
11334
11335
11336
11337
11338
11339
11340
11341
11342
11343
11344
11345
11346
11347
11348 /*
11349  * Based on:
11350  * Ext JS Library 1.1.1
11351  * Copyright(c) 2006-2007, Ext JS, LLC.
11352  *
11353  * Originally Released Under LGPL - original licence link has changed is not relivant.
11354  *
11355  * Fork - LGPL
11356  * <script type="text/javascript">
11357  */
11358
11359
11360
11361 //Notifies Element that fx methods are available
11362 Roo.enableFx = true;
11363
11364 /**
11365  * @class Roo.Fx
11366  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
11367  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
11368  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
11369  * Element effects to work.</p><br/>
11370  *
11371  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
11372  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
11373  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
11374  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
11375  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
11376  * expected results and should be done with care.</p><br/>
11377  *
11378  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
11379  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
11380 <pre>
11381 Value  Description
11382 -----  -----------------------------
11383 tl     The top left corner
11384 t      The center of the top edge
11385 tr     The top right corner
11386 l      The center of the left edge
11387 r      The center of the right edge
11388 bl     The bottom left corner
11389 b      The center of the bottom edge
11390 br     The bottom right corner
11391 </pre>
11392  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
11393  * below are common options that can be passed to any Fx method.</b>
11394  * @cfg {Function} callback A function called when the effect is finished
11395  * @cfg {Object} scope The scope of the effect function
11396  * @cfg {String} easing A valid Easing value for the effect
11397  * @cfg {String} afterCls A css class to apply after the effect
11398  * @cfg {Number} duration The length of time (in seconds) that the effect should last
11399  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
11400  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
11401  * effects that end with the element being visually hidden, ignored otherwise)
11402  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
11403  * a function which returns such a specification that will be applied to the Element after the effect finishes
11404  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
11405  * @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
11406  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
11407  */
11408 Roo.Fx = {
11409         /**
11410          * Slides the element into view.  An anchor point can be optionally passed to set the point of
11411          * origin for the slide effect.  This function automatically handles wrapping the element with
11412          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
11413          * Usage:
11414          *<pre><code>
11415 // default: slide the element in from the top
11416 el.slideIn();
11417
11418 // custom: slide the element in from the right with a 2-second duration
11419 el.slideIn('r', { duration: 2 });
11420
11421 // common config options shown with default values
11422 el.slideIn('t', {
11423     easing: 'easeOut',
11424     duration: .5
11425 });
11426 </code></pre>
11427          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
11428          * @param {Object} options (optional) Object literal with any of the Fx config options
11429          * @return {Roo.Element} The Element
11430          */
11431     slideIn : function(anchor, o){
11432         var el = this.getFxEl();
11433         o = o || {};
11434
11435         el.queueFx(o, function(){
11436
11437             anchor = anchor || "t";
11438
11439             // fix display to visibility
11440             this.fixDisplay();
11441
11442             // restore values after effect
11443             var r = this.getFxRestore();
11444             var b = this.getBox();
11445             // fixed size for slide
11446             this.setSize(b);
11447
11448             // wrap if needed
11449             var wrap = this.fxWrap(r.pos, o, "hidden");
11450
11451             var st = this.dom.style;
11452             st.visibility = "visible";
11453             st.position = "absolute";
11454
11455             // clear out temp styles after slide and unwrap
11456             var after = function(){
11457                 el.fxUnwrap(wrap, r.pos, o);
11458                 st.width = r.width;
11459                 st.height = r.height;
11460                 el.afterFx(o);
11461             };
11462             // time to calc the positions
11463             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
11464
11465             switch(anchor.toLowerCase()){
11466                 case "t":
11467                     wrap.setSize(b.width, 0);
11468                     st.left = st.bottom = "0";
11469                     a = {height: bh};
11470                 break;
11471                 case "l":
11472                     wrap.setSize(0, b.height);
11473                     st.right = st.top = "0";
11474                     a = {width: bw};
11475                 break;
11476                 case "r":
11477                     wrap.setSize(0, b.height);
11478                     wrap.setX(b.right);
11479                     st.left = st.top = "0";
11480                     a = {width: bw, points: pt};
11481                 break;
11482                 case "b":
11483                     wrap.setSize(b.width, 0);
11484                     wrap.setY(b.bottom);
11485                     st.left = st.top = "0";
11486                     a = {height: bh, points: pt};
11487                 break;
11488                 case "tl":
11489                     wrap.setSize(0, 0);
11490                     st.right = st.bottom = "0";
11491                     a = {width: bw, height: bh};
11492                 break;
11493                 case "bl":
11494                     wrap.setSize(0, 0);
11495                     wrap.setY(b.y+b.height);
11496                     st.right = st.top = "0";
11497                     a = {width: bw, height: bh, points: pt};
11498                 break;
11499                 case "br":
11500                     wrap.setSize(0, 0);
11501                     wrap.setXY([b.right, b.bottom]);
11502                     st.left = st.top = "0";
11503                     a = {width: bw, height: bh, points: pt};
11504                 break;
11505                 case "tr":
11506                     wrap.setSize(0, 0);
11507                     wrap.setX(b.x+b.width);
11508                     st.left = st.bottom = "0";
11509                     a = {width: bw, height: bh, points: pt};
11510                 break;
11511             }
11512             this.dom.style.visibility = "visible";
11513             wrap.show();
11514
11515             arguments.callee.anim = wrap.fxanim(a,
11516                 o,
11517                 'motion',
11518                 .5,
11519                 'easeOut', after);
11520         });
11521         return this;
11522     },
11523     
11524         /**
11525          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
11526          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
11527          * 'hidden') but block elements will still take up space in the document.  The element must be removed
11528          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
11529          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
11530          * Usage:
11531          *<pre><code>
11532 // default: slide the element out to the top
11533 el.slideOut();
11534
11535 // custom: slide the element out to the right with a 2-second duration
11536 el.slideOut('r', { duration: 2 });
11537
11538 // common config options shown with default values
11539 el.slideOut('t', {
11540     easing: 'easeOut',
11541     duration: .5,
11542     remove: false,
11543     useDisplay: false
11544 });
11545 </code></pre>
11546          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
11547          * @param {Object} options (optional) Object literal with any of the Fx config options
11548          * @return {Roo.Element} The Element
11549          */
11550     slideOut : function(anchor, o){
11551         var el = this.getFxEl();
11552         o = o || {};
11553
11554         el.queueFx(o, function(){
11555
11556             anchor = anchor || "t";
11557
11558             // restore values after effect
11559             var r = this.getFxRestore();
11560             
11561             var b = this.getBox();
11562             // fixed size for slide
11563             this.setSize(b);
11564
11565             // wrap if needed
11566             var wrap = this.fxWrap(r.pos, o, "visible");
11567
11568             var st = this.dom.style;
11569             st.visibility = "visible";
11570             st.position = "absolute";
11571
11572             wrap.setSize(b);
11573
11574             var after = function(){
11575                 if(o.useDisplay){
11576                     el.setDisplayed(false);
11577                 }else{
11578                     el.hide();
11579                 }
11580
11581                 el.fxUnwrap(wrap, r.pos, o);
11582
11583                 st.width = r.width;
11584                 st.height = r.height;
11585
11586                 el.afterFx(o);
11587             };
11588
11589             var a, zero = {to: 0};
11590             switch(anchor.toLowerCase()){
11591                 case "t":
11592                     st.left = st.bottom = "0";
11593                     a = {height: zero};
11594                 break;
11595                 case "l":
11596                     st.right = st.top = "0";
11597                     a = {width: zero};
11598                 break;
11599                 case "r":
11600                     st.left = st.top = "0";
11601                     a = {width: zero, points: {to:[b.right, b.y]}};
11602                 break;
11603                 case "b":
11604                     st.left = st.top = "0";
11605                     a = {height: zero, points: {to:[b.x, b.bottom]}};
11606                 break;
11607                 case "tl":
11608                     st.right = st.bottom = "0";
11609                     a = {width: zero, height: zero};
11610                 break;
11611                 case "bl":
11612                     st.right = st.top = "0";
11613                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
11614                 break;
11615                 case "br":
11616                     st.left = st.top = "0";
11617                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
11618                 break;
11619                 case "tr":
11620                     st.left = st.bottom = "0";
11621                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
11622                 break;
11623             }
11624
11625             arguments.callee.anim = wrap.fxanim(a,
11626                 o,
11627                 'motion',
11628                 .5,
11629                 "easeOut", after);
11630         });
11631         return this;
11632     },
11633
11634         /**
11635          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
11636          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
11637          * The element must be removed from the DOM using the 'remove' config option if desired.
11638          * Usage:
11639          *<pre><code>
11640 // default
11641 el.puff();
11642
11643 // common config options shown with default values
11644 el.puff({
11645     easing: 'easeOut',
11646     duration: .5,
11647     remove: false,
11648     useDisplay: false
11649 });
11650 </code></pre>
11651          * @param {Object} options (optional) Object literal with any of the Fx config options
11652          * @return {Roo.Element} The Element
11653          */
11654     puff : function(o){
11655         var el = this.getFxEl();
11656         o = o || {};
11657
11658         el.queueFx(o, function(){
11659             this.clearOpacity();
11660             this.show();
11661
11662             // restore values after effect
11663             var r = this.getFxRestore();
11664             var st = this.dom.style;
11665
11666             var after = function(){
11667                 if(o.useDisplay){
11668                     el.setDisplayed(false);
11669                 }else{
11670                     el.hide();
11671                 }
11672
11673                 el.clearOpacity();
11674
11675                 el.setPositioning(r.pos);
11676                 st.width = r.width;
11677                 st.height = r.height;
11678                 st.fontSize = '';
11679                 el.afterFx(o);
11680             };
11681
11682             var width = this.getWidth();
11683             var height = this.getHeight();
11684
11685             arguments.callee.anim = this.fxanim({
11686                     width : {to: this.adjustWidth(width * 2)},
11687                     height : {to: this.adjustHeight(height * 2)},
11688                     points : {by: [-(width * .5), -(height * .5)]},
11689                     opacity : {to: 0},
11690                     fontSize: {to:200, unit: "%"}
11691                 },
11692                 o,
11693                 'motion',
11694                 .5,
11695                 "easeOut", after);
11696         });
11697         return this;
11698     },
11699
11700         /**
11701          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
11702          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
11703          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
11704          * Usage:
11705          *<pre><code>
11706 // default
11707 el.switchOff();
11708
11709 // all config options shown with default values
11710 el.switchOff({
11711     easing: 'easeIn',
11712     duration: .3,
11713     remove: false,
11714     useDisplay: false
11715 });
11716 </code></pre>
11717          * @param {Object} options (optional) Object literal with any of the Fx config options
11718          * @return {Roo.Element} The Element
11719          */
11720     switchOff : function(o){
11721         var el = this.getFxEl();
11722         o = o || {};
11723
11724         el.queueFx(o, function(){
11725             this.clearOpacity();
11726             this.clip();
11727
11728             // restore values after effect
11729             var r = this.getFxRestore();
11730             var st = this.dom.style;
11731
11732             var after = function(){
11733                 if(o.useDisplay){
11734                     el.setDisplayed(false);
11735                 }else{
11736                     el.hide();
11737                 }
11738
11739                 el.clearOpacity();
11740                 el.setPositioning(r.pos);
11741                 st.width = r.width;
11742                 st.height = r.height;
11743
11744                 el.afterFx(o);
11745             };
11746
11747             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
11748                 this.clearOpacity();
11749                 (function(){
11750                     this.fxanim({
11751                         height:{to:1},
11752                         points:{by:[0, this.getHeight() * .5]}
11753                     }, o, 'motion', 0.3, 'easeIn', after);
11754                 }).defer(100, this);
11755             });
11756         });
11757         return this;
11758     },
11759
11760     /**
11761      * Highlights the Element by setting a color (applies to the background-color by default, but can be
11762      * changed using the "attr" config option) and then fading back to the original color. If no original
11763      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
11764      * Usage:
11765 <pre><code>
11766 // default: highlight background to yellow
11767 el.highlight();
11768
11769 // custom: highlight foreground text to blue for 2 seconds
11770 el.highlight("0000ff", { attr: 'color', duration: 2 });
11771
11772 // common config options shown with default values
11773 el.highlight("ffff9c", {
11774     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
11775     endColor: (current color) or "ffffff",
11776     easing: 'easeIn',
11777     duration: 1
11778 });
11779 </code></pre>
11780      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
11781      * @param {Object} options (optional) Object literal with any of the Fx config options
11782      * @return {Roo.Element} The Element
11783      */ 
11784     highlight : function(color, o){
11785         var el = this.getFxEl();
11786         o = o || {};
11787
11788         el.queueFx(o, function(){
11789             color = color || "ffff9c";
11790             attr = o.attr || "backgroundColor";
11791
11792             this.clearOpacity();
11793             this.show();
11794
11795             var origColor = this.getColor(attr);
11796             var restoreColor = this.dom.style[attr];
11797             endColor = (o.endColor || origColor) || "ffffff";
11798
11799             var after = function(){
11800                 el.dom.style[attr] = restoreColor;
11801                 el.afterFx(o);
11802             };
11803
11804             var a = {};
11805             a[attr] = {from: color, to: endColor};
11806             arguments.callee.anim = this.fxanim(a,
11807                 o,
11808                 'color',
11809                 1,
11810                 'easeIn', after);
11811         });
11812         return this;
11813     },
11814
11815    /**
11816     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
11817     * Usage:
11818 <pre><code>
11819 // default: a single light blue ripple
11820 el.frame();
11821
11822 // custom: 3 red ripples lasting 3 seconds total
11823 el.frame("ff0000", 3, { duration: 3 });
11824
11825 // common config options shown with default values
11826 el.frame("C3DAF9", 1, {
11827     duration: 1 //duration of entire animation (not each individual ripple)
11828     // Note: Easing is not configurable and will be ignored if included
11829 });
11830 </code></pre>
11831     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
11832     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
11833     * @param {Object} options (optional) Object literal with any of the Fx config options
11834     * @return {Roo.Element} The Element
11835     */
11836     frame : function(color, count, o){
11837         var el = this.getFxEl();
11838         o = o || {};
11839
11840         el.queueFx(o, function(){
11841             color = color || "#C3DAF9";
11842             if(color.length == 6){
11843                 color = "#" + color;
11844             }
11845             count = count || 1;
11846             duration = o.duration || 1;
11847             this.show();
11848
11849             var b = this.getBox();
11850             var animFn = function(){
11851                 var proxy = this.createProxy({
11852
11853                      style:{
11854                         visbility:"hidden",
11855                         position:"absolute",
11856                         "z-index":"35000", // yee haw
11857                         border:"0px solid " + color
11858                      }
11859                   });
11860                 var scale = Roo.isBorderBox ? 2 : 1;
11861                 proxy.animate({
11862                     top:{from:b.y, to:b.y - 20},
11863                     left:{from:b.x, to:b.x - 20},
11864                     borderWidth:{from:0, to:10},
11865                     opacity:{from:1, to:0},
11866                     height:{from:b.height, to:(b.height + (20*scale))},
11867                     width:{from:b.width, to:(b.width + (20*scale))}
11868                 }, duration, function(){
11869                     proxy.remove();
11870                 });
11871                 if(--count > 0){
11872                      animFn.defer((duration/2)*1000, this);
11873                 }else{
11874                     el.afterFx(o);
11875                 }
11876             };
11877             animFn.call(this);
11878         });
11879         return this;
11880     },
11881
11882    /**
11883     * Creates a pause before any subsequent queued effects begin.  If there are
11884     * no effects queued after the pause it will have no effect.
11885     * Usage:
11886 <pre><code>
11887 el.pause(1);
11888 </code></pre>
11889     * @param {Number} seconds The length of time to pause (in seconds)
11890     * @return {Roo.Element} The Element
11891     */
11892     pause : function(seconds){
11893         var el = this.getFxEl();
11894         var o = {};
11895
11896         el.queueFx(o, function(){
11897             setTimeout(function(){
11898                 el.afterFx(o);
11899             }, seconds * 1000);
11900         });
11901         return this;
11902     },
11903
11904    /**
11905     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
11906     * using the "endOpacity" config option.
11907     * Usage:
11908 <pre><code>
11909 // default: fade in from opacity 0 to 100%
11910 el.fadeIn();
11911
11912 // custom: fade in from opacity 0 to 75% over 2 seconds
11913 el.fadeIn({ endOpacity: .75, duration: 2});
11914
11915 // common config options shown with default values
11916 el.fadeIn({
11917     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
11918     easing: 'easeOut',
11919     duration: .5
11920 });
11921 </code></pre>
11922     * @param {Object} options (optional) Object literal with any of the Fx config options
11923     * @return {Roo.Element} The Element
11924     */
11925     fadeIn : function(o){
11926         var el = this.getFxEl();
11927         o = o || {};
11928         el.queueFx(o, function(){
11929             this.setOpacity(0);
11930             this.fixDisplay();
11931             this.dom.style.visibility = 'visible';
11932             var to = o.endOpacity || 1;
11933             arguments.callee.anim = this.fxanim({opacity:{to:to}},
11934                 o, null, .5, "easeOut", function(){
11935                 if(to == 1){
11936                     this.clearOpacity();
11937                 }
11938                 el.afterFx(o);
11939             });
11940         });
11941         return this;
11942     },
11943
11944    /**
11945     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
11946     * using the "endOpacity" config option.
11947     * Usage:
11948 <pre><code>
11949 // default: fade out from the element's current opacity to 0
11950 el.fadeOut();
11951
11952 // custom: fade out from the element's current opacity to 25% over 2 seconds
11953 el.fadeOut({ endOpacity: .25, duration: 2});
11954
11955 // common config options shown with default values
11956 el.fadeOut({
11957     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
11958     easing: 'easeOut',
11959     duration: .5
11960     remove: false,
11961     useDisplay: false
11962 });
11963 </code></pre>
11964     * @param {Object} options (optional) Object literal with any of the Fx config options
11965     * @return {Roo.Element} The Element
11966     */
11967     fadeOut : function(o){
11968         var el = this.getFxEl();
11969         o = o || {};
11970         el.queueFx(o, function(){
11971             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
11972                 o, null, .5, "easeOut", function(){
11973                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
11974                      this.dom.style.display = "none";
11975                 }else{
11976                      this.dom.style.visibility = "hidden";
11977                 }
11978                 this.clearOpacity();
11979                 el.afterFx(o);
11980             });
11981         });
11982         return this;
11983     },
11984
11985    /**
11986     * Animates the transition of an element's dimensions from a starting height/width
11987     * to an ending height/width.
11988     * Usage:
11989 <pre><code>
11990 // change height and width to 100x100 pixels
11991 el.scale(100, 100);
11992
11993 // common config options shown with default values.  The height and width will default to
11994 // the element's existing values if passed as null.
11995 el.scale(
11996     [element's width],
11997     [element's height], {
11998     easing: 'easeOut',
11999     duration: .35
12000 });
12001 </code></pre>
12002     * @param {Number} width  The new width (pass undefined to keep the original width)
12003     * @param {Number} height  The new height (pass undefined to keep the original height)
12004     * @param {Object} options (optional) Object literal with any of the Fx config options
12005     * @return {Roo.Element} The Element
12006     */
12007     scale : function(w, h, o){
12008         this.shift(Roo.apply({}, o, {
12009             width: w,
12010             height: h
12011         }));
12012         return this;
12013     },
12014
12015    /**
12016     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
12017     * Any of these properties not specified in the config object will not be changed.  This effect 
12018     * requires that at least one new dimension, position or opacity setting must be passed in on
12019     * the config object in order for the function to have any effect.
12020     * Usage:
12021 <pre><code>
12022 // slide the element horizontally to x position 200 while changing the height and opacity
12023 el.shift({ x: 200, height: 50, opacity: .8 });
12024
12025 // common config options shown with default values.
12026 el.shift({
12027     width: [element's width],
12028     height: [element's height],
12029     x: [element's x position],
12030     y: [element's y position],
12031     opacity: [element's opacity],
12032     easing: 'easeOut',
12033     duration: .35
12034 });
12035 </code></pre>
12036     * @param {Object} options  Object literal with any of the Fx config options
12037     * @return {Roo.Element} The Element
12038     */
12039     shift : function(o){
12040         var el = this.getFxEl();
12041         o = o || {};
12042         el.queueFx(o, function(){
12043             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
12044             if(w !== undefined){
12045                 a.width = {to: this.adjustWidth(w)};
12046             }
12047             if(h !== undefined){
12048                 a.height = {to: this.adjustHeight(h)};
12049             }
12050             if(x !== undefined || y !== undefined){
12051                 a.points = {to: [
12052                     x !== undefined ? x : this.getX(),
12053                     y !== undefined ? y : this.getY()
12054                 ]};
12055             }
12056             if(op !== undefined){
12057                 a.opacity = {to: op};
12058             }
12059             if(o.xy !== undefined){
12060                 a.points = {to: o.xy};
12061             }
12062             arguments.callee.anim = this.fxanim(a,
12063                 o, 'motion', .35, "easeOut", function(){
12064                 el.afterFx(o);
12065             });
12066         });
12067         return this;
12068     },
12069
12070         /**
12071          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
12072          * ending point of the effect.
12073          * Usage:
12074          *<pre><code>
12075 // default: slide the element downward while fading out
12076 el.ghost();
12077
12078 // custom: slide the element out to the right with a 2-second duration
12079 el.ghost('r', { duration: 2 });
12080
12081 // common config options shown with default values
12082 el.ghost('b', {
12083     easing: 'easeOut',
12084     duration: .5
12085     remove: false,
12086     useDisplay: false
12087 });
12088 </code></pre>
12089          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
12090          * @param {Object} options (optional) Object literal with any of the Fx config options
12091          * @return {Roo.Element} The Element
12092          */
12093     ghost : function(anchor, o){
12094         var el = this.getFxEl();
12095         o = o || {};
12096
12097         el.queueFx(o, function(){
12098             anchor = anchor || "b";
12099
12100             // restore values after effect
12101             var r = this.getFxRestore();
12102             var w = this.getWidth(),
12103                 h = this.getHeight();
12104
12105             var st = this.dom.style;
12106
12107             var after = function(){
12108                 if(o.useDisplay){
12109                     el.setDisplayed(false);
12110                 }else{
12111                     el.hide();
12112                 }
12113
12114                 el.clearOpacity();
12115                 el.setPositioning(r.pos);
12116                 st.width = r.width;
12117                 st.height = r.height;
12118
12119                 el.afterFx(o);
12120             };
12121
12122             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
12123             switch(anchor.toLowerCase()){
12124                 case "t":
12125                     pt.by = [0, -h];
12126                 break;
12127                 case "l":
12128                     pt.by = [-w, 0];
12129                 break;
12130                 case "r":
12131                     pt.by = [w, 0];
12132                 break;
12133                 case "b":
12134                     pt.by = [0, h];
12135                 break;
12136                 case "tl":
12137                     pt.by = [-w, -h];
12138                 break;
12139                 case "bl":
12140                     pt.by = [-w, h];
12141                 break;
12142                 case "br":
12143                     pt.by = [w, h];
12144                 break;
12145                 case "tr":
12146                     pt.by = [w, -h];
12147                 break;
12148             }
12149
12150             arguments.callee.anim = this.fxanim(a,
12151                 o,
12152                 'motion',
12153                 .5,
12154                 "easeOut", after);
12155         });
12156         return this;
12157     },
12158
12159         /**
12160          * Ensures that all effects queued after syncFx is called on the element are
12161          * run concurrently.  This is the opposite of {@link #sequenceFx}.
12162          * @return {Roo.Element} The Element
12163          */
12164     syncFx : function(){
12165         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
12166             block : false,
12167             concurrent : true,
12168             stopFx : false
12169         });
12170         return this;
12171     },
12172
12173         /**
12174          * Ensures that all effects queued after sequenceFx is called on the element are
12175          * run in sequence.  This is the opposite of {@link #syncFx}.
12176          * @return {Roo.Element} The Element
12177          */
12178     sequenceFx : function(){
12179         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
12180             block : false,
12181             concurrent : false,
12182             stopFx : false
12183         });
12184         return this;
12185     },
12186
12187         /* @private */
12188     nextFx : function(){
12189         var ef = this.fxQueue[0];
12190         if(ef){
12191             ef.call(this);
12192         }
12193     },
12194
12195         /**
12196          * Returns true if the element has any effects actively running or queued, else returns false.
12197          * @return {Boolean} True if element has active effects, else false
12198          */
12199     hasActiveFx : function(){
12200         return this.fxQueue && this.fxQueue[0];
12201     },
12202
12203         /**
12204          * Stops any running effects and clears the element's internal effects queue if it contains
12205          * any additional effects that haven't started yet.
12206          * @return {Roo.Element} The Element
12207          */
12208     stopFx : function(){
12209         if(this.hasActiveFx()){
12210             var cur = this.fxQueue[0];
12211             if(cur && cur.anim && cur.anim.isAnimated()){
12212                 this.fxQueue = [cur]; // clear out others
12213                 cur.anim.stop(true);
12214             }
12215         }
12216         return this;
12217     },
12218
12219         /* @private */
12220     beforeFx : function(o){
12221         if(this.hasActiveFx() && !o.concurrent){
12222            if(o.stopFx){
12223                this.stopFx();
12224                return true;
12225            }
12226            return false;
12227         }
12228         return true;
12229     },
12230
12231         /**
12232          * Returns true if the element is currently blocking so that no other effect can be queued
12233          * until this effect is finished, else returns false if blocking is not set.  This is commonly
12234          * used to ensure that an effect initiated by a user action runs to completion prior to the
12235          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
12236          * @return {Boolean} True if blocking, else false
12237          */
12238     hasFxBlock : function(){
12239         var q = this.fxQueue;
12240         return q && q[0] && q[0].block;
12241     },
12242
12243         /* @private */
12244     queueFx : function(o, fn){
12245         if(!this.fxQueue){
12246             this.fxQueue = [];
12247         }
12248         if(!this.hasFxBlock()){
12249             Roo.applyIf(o, this.fxDefaults);
12250             if(!o.concurrent){
12251                 var run = this.beforeFx(o);
12252                 fn.block = o.block;
12253                 this.fxQueue.push(fn);
12254                 if(run){
12255                     this.nextFx();
12256                 }
12257             }else{
12258                 fn.call(this);
12259             }
12260         }
12261         return this;
12262     },
12263
12264         /* @private */
12265     fxWrap : function(pos, o, vis){
12266         var wrap;
12267         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
12268             var wrapXY;
12269             if(o.fixPosition){
12270                 wrapXY = this.getXY();
12271             }
12272             var div = document.createElement("div");
12273             div.style.visibility = vis;
12274             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
12275             wrap.setPositioning(pos);
12276             if(wrap.getStyle("position") == "static"){
12277                 wrap.position("relative");
12278             }
12279             this.clearPositioning('auto');
12280             wrap.clip();
12281             wrap.dom.appendChild(this.dom);
12282             if(wrapXY){
12283                 wrap.setXY(wrapXY);
12284             }
12285         }
12286         return wrap;
12287     },
12288
12289         /* @private */
12290     fxUnwrap : function(wrap, pos, o){
12291         this.clearPositioning();
12292         this.setPositioning(pos);
12293         if(!o.wrap){
12294             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
12295             wrap.remove();
12296         }
12297     },
12298
12299         /* @private */
12300     getFxRestore : function(){
12301         var st = this.dom.style;
12302         return {pos: this.getPositioning(), width: st.width, height : st.height};
12303     },
12304
12305         /* @private */
12306     afterFx : function(o){
12307         if(o.afterStyle){
12308             this.applyStyles(o.afterStyle);
12309         }
12310         if(o.afterCls){
12311             this.addClass(o.afterCls);
12312         }
12313         if(o.remove === true){
12314             this.remove();
12315         }
12316         Roo.callback(o.callback, o.scope, [this]);
12317         if(!o.concurrent){
12318             this.fxQueue.shift();
12319             this.nextFx();
12320         }
12321     },
12322
12323         /* @private */
12324     getFxEl : function(){ // support for composite element fx
12325         return Roo.get(this.dom);
12326     },
12327
12328         /* @private */
12329     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
12330         animType = animType || 'run';
12331         opt = opt || {};
12332         var anim = Roo.lib.Anim[animType](
12333             this.dom, args,
12334             (opt.duration || defaultDur) || .35,
12335             (opt.easing || defaultEase) || 'easeOut',
12336             function(){
12337                 Roo.callback(cb, this);
12338             },
12339             this
12340         );
12341         opt.anim = anim;
12342         return anim;
12343     }
12344 };
12345
12346 // backwords compat
12347 Roo.Fx.resize = Roo.Fx.scale;
12348
12349 //When included, Roo.Fx is automatically applied to Element so that all basic
12350 //effects are available directly via the Element API
12351 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
12352  * Based on:
12353  * Ext JS Library 1.1.1
12354  * Copyright(c) 2006-2007, Ext JS, LLC.
12355  *
12356  * Originally Released Under LGPL - original licence link has changed is not relivant.
12357  *
12358  * Fork - LGPL
12359  * <script type="text/javascript">
12360  */
12361
12362
12363 /**
12364  * @class Roo.CompositeElement
12365  * Standard composite class. Creates a Roo.Element for every element in the collection.
12366  * <br><br>
12367  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
12368  * actions will be performed on all the elements in this collection.</b>
12369  * <br><br>
12370  * All methods return <i>this</i> and can be chained.
12371  <pre><code>
12372  var els = Roo.select("#some-el div.some-class", true);
12373  // or select directly from an existing element
12374  var el = Roo.get('some-el');
12375  el.select('div.some-class', true);
12376
12377  els.setWidth(100); // all elements become 100 width
12378  els.hide(true); // all elements fade out and hide
12379  // or
12380  els.setWidth(100).hide(true);
12381  </code></pre>
12382  */
12383 Roo.CompositeElement = function(els){
12384     this.elements = [];
12385     this.addElements(els);
12386 };
12387 Roo.CompositeElement.prototype = {
12388     isComposite: true,
12389     addElements : function(els){
12390         if(!els) {
12391             return this;
12392         }
12393         if(typeof els == "string"){
12394             els = Roo.Element.selectorFunction(els);
12395         }
12396         var yels = this.elements;
12397         var index = yels.length-1;
12398         for(var i = 0, len = els.length; i < len; i++) {
12399                 yels[++index] = Roo.get(els[i]);
12400         }
12401         return this;
12402     },
12403
12404     /**
12405     * Clears this composite and adds the elements returned by the passed selector.
12406     * @param {String/Array} els A string CSS selector, an array of elements or an element
12407     * @return {CompositeElement} this
12408     */
12409     fill : function(els){
12410         this.elements = [];
12411         this.add(els);
12412         return this;
12413     },
12414
12415     /**
12416     * Filters this composite to only elements that match the passed selector.
12417     * @param {String} selector A string CSS selector
12418     * @param {Boolean} inverse return inverse filter (not matches)
12419     * @return {CompositeElement} this
12420     */
12421     filter : function(selector, inverse){
12422         var els = [];
12423         inverse = inverse || false;
12424         this.each(function(el){
12425             var match = inverse ? !el.is(selector) : el.is(selector);
12426             if(match){
12427                 els[els.length] = el.dom;
12428             }
12429         });
12430         this.fill(els);
12431         return this;
12432     },
12433
12434     invoke : function(fn, args){
12435         var els = this.elements;
12436         for(var i = 0, len = els.length; i < len; i++) {
12437                 Roo.Element.prototype[fn].apply(els[i], args);
12438         }
12439         return this;
12440     },
12441     /**
12442     * Adds elements to this composite.
12443     * @param {String/Array} els A string CSS selector, an array of elements or an element
12444     * @return {CompositeElement} this
12445     */
12446     add : function(els){
12447         if(typeof els == "string"){
12448             this.addElements(Roo.Element.selectorFunction(els));
12449         }else if(els.length !== undefined){
12450             this.addElements(els);
12451         }else{
12452             this.addElements([els]);
12453         }
12454         return this;
12455     },
12456     /**
12457     * Calls the passed function passing (el, this, index) for each element in this composite.
12458     * @param {Function} fn The function to call
12459     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
12460     * @return {CompositeElement} this
12461     */
12462     each : function(fn, scope){
12463         var els = this.elements;
12464         for(var i = 0, len = els.length; i < len; i++){
12465             if(fn.call(scope || els[i], els[i], this, i) === false) {
12466                 break;
12467             }
12468         }
12469         return this;
12470     },
12471
12472     /**
12473      * Returns the Element object at the specified index
12474      * @param {Number} index
12475      * @return {Roo.Element}
12476      */
12477     item : function(index){
12478         return this.elements[index] || null;
12479     },
12480
12481     /**
12482      * Returns the first Element
12483      * @return {Roo.Element}
12484      */
12485     first : function(){
12486         return this.item(0);
12487     },
12488
12489     /**
12490      * Returns the last Element
12491      * @return {Roo.Element}
12492      */
12493     last : function(){
12494         return this.item(this.elements.length-1);
12495     },
12496
12497     /**
12498      * Returns the number of elements in this composite
12499      * @return Number
12500      */
12501     getCount : function(){
12502         return this.elements.length;
12503     },
12504
12505     /**
12506      * Returns true if this composite contains the passed element
12507      * @return Boolean
12508      */
12509     contains : function(el){
12510         return this.indexOf(el) !== -1;
12511     },
12512
12513     /**
12514      * Returns true if this composite contains the passed element
12515      * @return Boolean
12516      */
12517     indexOf : function(el){
12518         return this.elements.indexOf(Roo.get(el));
12519     },
12520
12521
12522     /**
12523     * Removes the specified element(s).
12524     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
12525     * or an array of any of those.
12526     * @param {Boolean} removeDom (optional) True to also remove the element from the document
12527     * @return {CompositeElement} this
12528     */
12529     removeElement : function(el, removeDom){
12530         if(el instanceof Array){
12531             for(var i = 0, len = el.length; i < len; i++){
12532                 this.removeElement(el[i]);
12533             }
12534             return this;
12535         }
12536         var index = typeof el == 'number' ? el : this.indexOf(el);
12537         if(index !== -1){
12538             if(removeDom){
12539                 var d = this.elements[index];
12540                 if(d.dom){
12541                     d.remove();
12542                 }else{
12543                     d.parentNode.removeChild(d);
12544                 }
12545             }
12546             this.elements.splice(index, 1);
12547         }
12548         return this;
12549     },
12550
12551     /**
12552     * Replaces the specified element with the passed element.
12553     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
12554     * to replace.
12555     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
12556     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
12557     * @return {CompositeElement} this
12558     */
12559     replaceElement : function(el, replacement, domReplace){
12560         var index = typeof el == 'number' ? el : this.indexOf(el);
12561         if(index !== -1){
12562             if(domReplace){
12563                 this.elements[index].replaceWith(replacement);
12564             }else{
12565                 this.elements.splice(index, 1, Roo.get(replacement))
12566             }
12567         }
12568         return this;
12569     },
12570
12571     /**
12572      * Removes all elements.
12573      */
12574     clear : function(){
12575         this.elements = [];
12576     }
12577 };
12578 (function(){
12579     Roo.CompositeElement.createCall = function(proto, fnName){
12580         if(!proto[fnName]){
12581             proto[fnName] = function(){
12582                 return this.invoke(fnName, arguments);
12583             };
12584         }
12585     };
12586     for(var fnName in Roo.Element.prototype){
12587         if(typeof Roo.Element.prototype[fnName] == "function"){
12588             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
12589         }
12590     };
12591 })();
12592 /*
12593  * Based on:
12594  * Ext JS Library 1.1.1
12595  * Copyright(c) 2006-2007, Ext JS, LLC.
12596  *
12597  * Originally Released Under LGPL - original licence link has changed is not relivant.
12598  *
12599  * Fork - LGPL
12600  * <script type="text/javascript">
12601  */
12602
12603 /**
12604  * @class Roo.CompositeElementLite
12605  * @extends Roo.CompositeElement
12606  * Flyweight composite class. Reuses the same Roo.Element for element operations.
12607  <pre><code>
12608  var els = Roo.select("#some-el div.some-class");
12609  // or select directly from an existing element
12610  var el = Roo.get('some-el');
12611  el.select('div.some-class');
12612
12613  els.setWidth(100); // all elements become 100 width
12614  els.hide(true); // all elements fade out and hide
12615  // or
12616  els.setWidth(100).hide(true);
12617  </code></pre><br><br>
12618  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
12619  * actions will be performed on all the elements in this collection.</b>
12620  */
12621 Roo.CompositeElementLite = function(els){
12622     Roo.CompositeElementLite.superclass.constructor.call(this, els);
12623     this.el = new Roo.Element.Flyweight();
12624 };
12625 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
12626     addElements : function(els){
12627         if(els){
12628             if(els instanceof Array){
12629                 this.elements = this.elements.concat(els);
12630             }else{
12631                 var yels = this.elements;
12632                 var index = yels.length-1;
12633                 for(var i = 0, len = els.length; i < len; i++) {
12634                     yels[++index] = els[i];
12635                 }
12636             }
12637         }
12638         return this;
12639     },
12640     invoke : function(fn, args){
12641         var els = this.elements;
12642         var el = this.el;
12643         for(var i = 0, len = els.length; i < len; i++) {
12644             el.dom = els[i];
12645                 Roo.Element.prototype[fn].apply(el, args);
12646         }
12647         return this;
12648     },
12649     /**
12650      * Returns a flyweight Element of the dom element object at the specified index
12651      * @param {Number} index
12652      * @return {Roo.Element}
12653      */
12654     item : function(index){
12655         if(!this.elements[index]){
12656             return null;
12657         }
12658         this.el.dom = this.elements[index];
12659         return this.el;
12660     },
12661
12662     // fixes scope with flyweight
12663     addListener : function(eventName, handler, scope, opt){
12664         var els = this.elements;
12665         for(var i = 0, len = els.length; i < len; i++) {
12666             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
12667         }
12668         return this;
12669     },
12670
12671     /**
12672     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
12673     * passed is the flyweight (shared) Roo.Element instance, so if you require a
12674     * a reference to the dom node, use el.dom.</b>
12675     * @param {Function} fn The function to call
12676     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
12677     * @return {CompositeElement} this
12678     */
12679     each : function(fn, scope){
12680         var els = this.elements;
12681         var el = this.el;
12682         for(var i = 0, len = els.length; i < len; i++){
12683             el.dom = els[i];
12684                 if(fn.call(scope || el, el, this, i) === false){
12685                 break;
12686             }
12687         }
12688         return this;
12689     },
12690
12691     indexOf : function(el){
12692         return this.elements.indexOf(Roo.getDom(el));
12693     },
12694
12695     replaceElement : function(el, replacement, domReplace){
12696         var index = typeof el == 'number' ? el : this.indexOf(el);
12697         if(index !== -1){
12698             replacement = Roo.getDom(replacement);
12699             if(domReplace){
12700                 var d = this.elements[index];
12701                 d.parentNode.insertBefore(replacement, d);
12702                 d.parentNode.removeChild(d);
12703             }
12704             this.elements.splice(index, 1, replacement);
12705         }
12706         return this;
12707     }
12708 });
12709 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
12710
12711 /*
12712  * Based on:
12713  * Ext JS Library 1.1.1
12714  * Copyright(c) 2006-2007, Ext JS, LLC.
12715  *
12716  * Originally Released Under LGPL - original licence link has changed is not relivant.
12717  *
12718  * Fork - LGPL
12719  * <script type="text/javascript">
12720  */
12721
12722  
12723
12724 /**
12725  * @class Roo.data.Connection
12726  * @extends Roo.util.Observable
12727  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
12728  * either to a configured URL, or to a URL specified at request time. 
12729  * 
12730  * Requests made by this class are asynchronous, and will return immediately. No data from
12731  * the server will be available to the statement immediately following the {@link #request} call.
12732  * To process returned data, use a callback in the request options object, or an event listener.
12733  * 
12734  * Note: If you are doing a file upload, you will not get a normal response object sent back to
12735  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
12736  * The response object is created using the innerHTML of the IFRAME's document as the responseText
12737  * property and, if present, the IFRAME's XML document as the responseXML property.
12738  * 
12739  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
12740  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
12741  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
12742  * standard DOM methods.
12743  * @constructor
12744  * @param {Object} config a configuration object.
12745  */
12746 Roo.data.Connection = function(config){
12747     Roo.apply(this, config);
12748     this.addEvents({
12749         /**
12750          * @event beforerequest
12751          * Fires before a network request is made to retrieve a data object.
12752          * @param {Connection} conn This Connection object.
12753          * @param {Object} options The options config object passed to the {@link #request} method.
12754          */
12755         "beforerequest" : true,
12756         /**
12757          * @event requestcomplete
12758          * Fires if the request was successfully completed.
12759          * @param {Connection} conn This Connection object.
12760          * @param {Object} response The XHR object containing the response data.
12761          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
12762          * @param {Object} options The options config object passed to the {@link #request} method.
12763          */
12764         "requestcomplete" : true,
12765         /**
12766          * @event requestexception
12767          * Fires if an error HTTP status was returned from the server.
12768          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
12769          * @param {Connection} conn This Connection object.
12770          * @param {Object} response The XHR object containing the response data.
12771          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
12772          * @param {Object} options The options config object passed to the {@link #request} method.
12773          */
12774         "requestexception" : true
12775     });
12776     Roo.data.Connection.superclass.constructor.call(this);
12777 };
12778
12779 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
12780     /**
12781      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12782      */
12783     /**
12784      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12785      * extra parameters to each request made by this object. (defaults to undefined)
12786      */
12787     /**
12788      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12789      *  to each request made by this object. (defaults to undefined)
12790      */
12791     /**
12792      * @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)
12793      */
12794     /**
12795      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12796      */
12797     timeout : 30000,
12798     /**
12799      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12800      * @type Boolean
12801      */
12802     autoAbort:false,
12803
12804     /**
12805      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12806      * @type Boolean
12807      */
12808     disableCaching: true,
12809
12810     /**
12811      * Sends an HTTP request to a remote server.
12812      * @param {Object} options An object which may contain the following properties:<ul>
12813      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
12814      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
12815      * request, a url encoded string or a function to call to get either.</li>
12816      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
12817      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
12818      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
12819      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
12820      * <li>options {Object} The parameter to the request call.</li>
12821      * <li>success {Boolean} True if the request succeeded.</li>
12822      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
12823      * </ul></li>
12824      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
12825      * The callback is passed the following parameters:<ul>
12826      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
12827      * <li>options {Object} The parameter to the request call.</li>
12828      * </ul></li>
12829      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
12830      * The callback is passed the following parameters:<ul>
12831      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
12832      * <li>options {Object} The parameter to the request call.</li>
12833      * </ul></li>
12834      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
12835      * for the callback function. Defaults to the browser window.</li>
12836      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
12837      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
12838      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
12839      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
12840      * params for the post data. Any params will be appended to the URL.</li>
12841      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
12842      * </ul>
12843      * @return {Number} transactionId
12844      */
12845     request : function(o){
12846         if(this.fireEvent("beforerequest", this, o) !== false){
12847             var p = o.params;
12848
12849             if(typeof p == "function"){
12850                 p = p.call(o.scope||window, o);
12851             }
12852             if(typeof p == "object"){
12853                 p = Roo.urlEncode(o.params);
12854             }
12855             if(this.extraParams){
12856                 var extras = Roo.urlEncode(this.extraParams);
12857                 p = p ? (p + '&' + extras) : extras;
12858             }
12859
12860             var url = o.url || this.url;
12861             if(typeof url == 'function'){
12862                 url = url.call(o.scope||window, o);
12863             }
12864
12865             if(o.form){
12866                 var form = Roo.getDom(o.form);
12867                 url = url || form.action;
12868
12869                 var enctype = form.getAttribute("enctype");
12870                 
12871                 if (o.formData) {
12872                     return this.doFormDataUpload(o, url);
12873                 }
12874                 
12875                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
12876                     return this.doFormUpload(o, p, url);
12877                 }
12878                 var f = Roo.lib.Ajax.serializeForm(form);
12879                 p = p ? (p + '&' + f) : f;
12880             }
12881             
12882             if (!o.form && o.formData) {
12883                 o.formData = o.formData === true ? new FormData() : o.formData;
12884                 for (var k in o.params) {
12885                     o.formData.append(k,o.params[k]);
12886                 }
12887                     
12888                 return this.doFormDataUpload(o, url);
12889             }
12890             
12891
12892             var hs = o.headers;
12893             if(this.defaultHeaders){
12894                 hs = Roo.apply(hs || {}, this.defaultHeaders);
12895                 if(!o.headers){
12896                     o.headers = hs;
12897                 }
12898             }
12899
12900             var cb = {
12901                 success: this.handleResponse,
12902                 failure: this.handleFailure,
12903                 scope: this,
12904                 argument: {options: o},
12905                 timeout : o.timeout || this.timeout
12906             };
12907
12908             var method = o.method||this.method||(p ? "POST" : "GET");
12909
12910             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
12911                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
12912             }
12913
12914             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
12915                 if(o.autoAbort){
12916                     this.abort();
12917                 }
12918             }else if(this.autoAbort !== false){
12919                 this.abort();
12920             }
12921
12922             if((method == 'GET' && p) || o.xmlData){
12923                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
12924                 p = '';
12925             }
12926             Roo.lib.Ajax.useDefaultHeader = typeof(o.headers) == 'undefined' || typeof(o.headers['Content-Type']) == 'undefined';
12927             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
12928             Roo.lib.Ajax.useDefaultHeader == true;
12929             return this.transId;
12930         }else{
12931             Roo.callback(o.callback, o.scope, [o, null, null]);
12932             return null;
12933         }
12934     },
12935
12936     /**
12937      * Determine whether this object has a request outstanding.
12938      * @param {Number} transactionId (Optional) defaults to the last transaction
12939      * @return {Boolean} True if there is an outstanding request.
12940      */
12941     isLoading : function(transId){
12942         if(transId){
12943             return Roo.lib.Ajax.isCallInProgress(transId);
12944         }else{
12945             return this.transId ? true : false;
12946         }
12947     },
12948
12949     /**
12950      * Aborts any outstanding request.
12951      * @param {Number} transactionId (Optional) defaults to the last transaction
12952      */
12953     abort : function(transId){
12954         if(transId || this.isLoading()){
12955             Roo.lib.Ajax.abort(transId || this.transId);
12956         }
12957     },
12958
12959     // private
12960     handleResponse : function(response){
12961         this.transId = false;
12962         var options = response.argument.options;
12963         response.argument = options ? options.argument : null;
12964         this.fireEvent("requestcomplete", this, response, options);
12965         Roo.callback(options.success, options.scope, [response, options]);
12966         Roo.callback(options.callback, options.scope, [options, true, response]);
12967     },
12968
12969     // private
12970     handleFailure : function(response, e){
12971         this.transId = false;
12972         var options = response.argument.options;
12973         response.argument = options ? options.argument : null;
12974         this.fireEvent("requestexception", this, response, options, e);
12975         Roo.callback(options.failure, options.scope, [response, options]);
12976         Roo.callback(options.callback, options.scope, [options, false, response]);
12977     },
12978
12979     // private
12980     doFormUpload : function(o, ps, url){
12981         var id = Roo.id();
12982         var frame = document.createElement('iframe');
12983         frame.id = id;
12984         frame.name = id;
12985         frame.className = 'x-hidden';
12986         if(Roo.isIE){
12987             frame.src = Roo.SSL_SECURE_URL;
12988         }
12989         document.body.appendChild(frame);
12990
12991         if(Roo.isIE){
12992            document.frames[id].name = id;
12993         }
12994
12995         var form = Roo.getDom(o.form);
12996         form.target = id;
12997         form.method = 'POST';
12998         form.enctype = form.encoding = 'multipart/form-data';
12999         if(url){
13000             form.action = url;
13001         }
13002
13003         var hiddens, hd;
13004         if(ps){ // add dynamic params
13005             hiddens = [];
13006             ps = Roo.urlDecode(ps, false);
13007             for(var k in ps){
13008                 if(ps.hasOwnProperty(k)){
13009                     hd = document.createElement('input');
13010                     hd.type = 'hidden';
13011                     hd.name = k;
13012                     hd.value = ps[k];
13013                     form.appendChild(hd);
13014                     hiddens.push(hd);
13015                 }
13016             }
13017         }
13018
13019         function cb(){
13020             var r = {  // bogus response object
13021                 responseText : '',
13022                 responseXML : null
13023             };
13024
13025             r.argument = o ? o.argument : null;
13026
13027             try { //
13028                 var doc;
13029                 if(Roo.isIE){
13030                     doc = frame.contentWindow.document;
13031                 }else {
13032                     doc = (frame.contentDocument || window.frames[id].document);
13033                 }
13034                 if(doc && doc.body){
13035                     r.responseText = doc.body.innerHTML;
13036                 }
13037                 if(doc && doc.XMLDocument){
13038                     r.responseXML = doc.XMLDocument;
13039                 }else {
13040                     r.responseXML = doc;
13041                 }
13042             }
13043             catch(e) {
13044                 // ignore
13045             }
13046
13047             Roo.EventManager.removeListener(frame, 'load', cb, this);
13048
13049             this.fireEvent("requestcomplete", this, r, o);
13050             Roo.callback(o.success, o.scope, [r, o]);
13051             Roo.callback(o.callback, o.scope, [o, true, r]);
13052
13053             setTimeout(function(){document.body.removeChild(frame);}, 100);
13054         }
13055
13056         Roo.EventManager.on(frame, 'load', cb, this);
13057         form.submit();
13058
13059         if(hiddens){ // remove dynamic params
13060             for(var i = 0, len = hiddens.length; i < len; i++){
13061                 form.removeChild(hiddens[i]);
13062             }
13063         }
13064     },
13065     // this is a 'formdata version???'
13066     
13067     
13068     doFormDataUpload : function(o,  url)
13069     {
13070         var formData;
13071         if (o.form) {
13072             var form =  Roo.getDom(o.form);
13073             form.enctype = form.encoding = 'multipart/form-data';
13074             formData = o.formData === true ? new FormData(form) : o.formData;
13075         } else {
13076             formData = o.formData === true ? new FormData() : o.formData;
13077         }
13078         
13079       
13080         var cb = {
13081             success: this.handleResponse,
13082             failure: this.handleFailure,
13083             scope: this,
13084             argument: {options: o},
13085             timeout : o.timeout || this.timeout
13086         };
13087  
13088         if(typeof o.autoAbort == 'boolean'){ // options gets top priority
13089             if(o.autoAbort){
13090                 this.abort();
13091             }
13092         }else if(this.autoAbort !== false){
13093             this.abort();
13094         }
13095
13096         //Roo.lib.Ajax.defaultPostHeader = null;
13097         Roo.lib.Ajax.useDefaultHeader = false;
13098         this.transId = Roo.lib.Ajax.request( "POST", url, cb,  formData, o);
13099         Roo.lib.Ajax.useDefaultHeader = true;
13100  
13101          
13102     }
13103     
13104 });
13105 /*
13106  * Based on:
13107  * Ext JS Library 1.1.1
13108  * Copyright(c) 2006-2007, Ext JS, LLC.
13109  *
13110  * Originally Released Under LGPL - original licence link has changed is not relivant.
13111  *
13112  * Fork - LGPL
13113  * <script type="text/javascript">
13114  */
13115  
13116 /**
13117  * Global Ajax request class.
13118  * 
13119  * @class Roo.Ajax
13120  * @extends Roo.data.Connection
13121  * @static
13122  * 
13123  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
13124  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
13125  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
13126  * @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)
13127  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
13128  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
13129  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
13130  */
13131 Roo.Ajax = new Roo.data.Connection({
13132     // fix up the docs
13133     /**
13134      * @scope Roo.Ajax
13135      * @type {Boolear} 
13136      */
13137     autoAbort : false,
13138
13139     /**
13140      * Serialize the passed form into a url encoded string
13141      * @scope Roo.Ajax
13142      * @param {String/HTMLElement} form
13143      * @return {String}
13144      */
13145     serializeForm : function(form){
13146         return Roo.lib.Ajax.serializeForm(form);
13147     }
13148 });/*
13149  * Based on:
13150  * Ext JS Library 1.1.1
13151  * Copyright(c) 2006-2007, Ext JS, LLC.
13152  *
13153  * Originally Released Under LGPL - original licence link has changed is not relivant.
13154  *
13155  * Fork - LGPL
13156  * <script type="text/javascript">
13157  */
13158
13159  
13160 /**
13161  * @class Roo.UpdateManager
13162  * @extends Roo.util.Observable
13163  * Provides AJAX-style update for Element object.<br><br>
13164  * Usage:<br>
13165  * <pre><code>
13166  * // Get it from a Roo.Element object
13167  * var el = Roo.get("foo");
13168  * var mgr = el.getUpdateManager();
13169  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
13170  * ...
13171  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
13172  * <br>
13173  * // or directly (returns the same UpdateManager instance)
13174  * var mgr = new Roo.UpdateManager("myElementId");
13175  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
13176  * mgr.on("update", myFcnNeedsToKnow);
13177  * <br>
13178    // short handed call directly from the element object
13179    Roo.get("foo").load({
13180         url: "bar.php",
13181         scripts:true,
13182         params: "for=bar",
13183         text: "Loading Foo..."
13184    });
13185  * </code></pre>
13186  * @constructor
13187  * Create new UpdateManager directly.
13188  * @param {String/HTMLElement/Roo.Element} el The element to update
13189  * @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).
13190  */
13191 Roo.UpdateManager = function(el, forceNew){
13192     el = Roo.get(el);
13193     if(!forceNew && el.updateManager){
13194         return el.updateManager;
13195     }
13196     /**
13197      * The Element object
13198      * @type Roo.Element
13199      */
13200     this.el = el;
13201     /**
13202      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
13203      * @type String
13204      */
13205     this.defaultUrl = null;
13206
13207     this.addEvents({
13208         /**
13209          * @event beforeupdate
13210          * Fired before an update is made, return false from your handler and the update is cancelled.
13211          * @param {Roo.Element} el
13212          * @param {String/Object/Function} url
13213          * @param {String/Object} params
13214          */
13215         "beforeupdate": true,
13216         /**
13217          * @event update
13218          * Fired after successful update is made.
13219          * @param {Roo.Element} el
13220          * @param {Object} oResponseObject The response Object
13221          */
13222         "update": true,
13223         /**
13224          * @event failure
13225          * Fired on update failure.
13226          * @param {Roo.Element} el
13227          * @param {Object} oResponseObject The response Object
13228          */
13229         "failure": true
13230     });
13231     var d = Roo.UpdateManager.defaults;
13232     /**
13233      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
13234      * @type String
13235      */
13236     this.sslBlankUrl = d.sslBlankUrl;
13237     /**
13238      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
13239      * @type Boolean
13240      */
13241     this.disableCaching = d.disableCaching;
13242     /**
13243      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
13244      * @type String
13245      */
13246     this.indicatorText = d.indicatorText;
13247     /**
13248      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
13249      * @type String
13250      */
13251     this.showLoadIndicator = d.showLoadIndicator;
13252     /**
13253      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
13254      * @type Number
13255      */
13256     this.timeout = d.timeout;
13257
13258     /**
13259      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
13260      * @type Boolean
13261      */
13262     this.loadScripts = d.loadScripts;
13263
13264     /**
13265      * Transaction object of current executing transaction
13266      */
13267     this.transaction = null;
13268
13269     /**
13270      * @private
13271      */
13272     this.autoRefreshProcId = null;
13273     /**
13274      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
13275      * @type Function
13276      */
13277     this.refreshDelegate = this.refresh.createDelegate(this);
13278     /**
13279      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
13280      * @type Function
13281      */
13282     this.updateDelegate = this.update.createDelegate(this);
13283     /**
13284      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
13285      * @type Function
13286      */
13287     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
13288     /**
13289      * @private
13290      */
13291     this.successDelegate = this.processSuccess.createDelegate(this);
13292     /**
13293      * @private
13294      */
13295     this.failureDelegate = this.processFailure.createDelegate(this);
13296
13297     if(!this.renderer){
13298      /**
13299       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
13300       */
13301     this.renderer = new Roo.UpdateManager.BasicRenderer();
13302     }
13303     
13304     Roo.UpdateManager.superclass.constructor.call(this);
13305 };
13306
13307 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
13308     /**
13309      * Get the Element this UpdateManager is bound to
13310      * @return {Roo.Element} The element
13311      */
13312     getEl : function(){
13313         return this.el;
13314     },
13315     /**
13316      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
13317      * @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:
13318 <pre><code>
13319 um.update({<br/>
13320     url: "your-url.php",<br/>
13321     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
13322     callback: yourFunction,<br/>
13323     scope: yourObject, //(optional scope)  <br/>
13324     discardUrl: false, <br/>
13325     nocache: false,<br/>
13326     text: "Loading...",<br/>
13327     timeout: 30,<br/>
13328     scripts: false<br/>
13329 });
13330 </code></pre>
13331      * The only required property is url. The optional properties nocache, text and scripts
13332      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
13333      * @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}
13334      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
13335      * @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.
13336      */
13337     update : function(url, params, callback, discardUrl){
13338         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
13339             var method = this.method,
13340                 cfg;
13341             if(typeof url == "object"){ // must be config object
13342                 cfg = url;
13343                 url = cfg.url;
13344                 params = params || cfg.params;
13345                 callback = callback || cfg.callback;
13346                 discardUrl = discardUrl || cfg.discardUrl;
13347                 if(callback && cfg.scope){
13348                     callback = callback.createDelegate(cfg.scope);
13349                 }
13350                 if(typeof cfg.method != "undefined"){method = cfg.method;};
13351                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
13352                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
13353                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
13354                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
13355             }
13356             this.showLoading();
13357             if(!discardUrl){
13358                 this.defaultUrl = url;
13359             }
13360             if(typeof url == "function"){
13361                 url = url.call(this);
13362             }
13363
13364             method = method || (params ? "POST" : "GET");
13365             if(method == "GET"){
13366                 url = this.prepareUrl(url);
13367             }
13368
13369             var o = Roo.apply(cfg ||{}, {
13370                 url : url,
13371                 params: params,
13372                 success: this.successDelegate,
13373                 failure: this.failureDelegate,
13374                 callback: undefined,
13375                 timeout: (this.timeout*1000),
13376                 argument: {"url": url, "form": null, "callback": callback, "params": params}
13377             });
13378             Roo.log("updated manager called with timeout of " + o.timeout);
13379             this.transaction = Roo.Ajax.request(o);
13380         }
13381     },
13382
13383     /**
13384      * 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.
13385      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
13386      * @param {String/HTMLElement} form The form Id or form element
13387      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
13388      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
13389      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
13390      */
13391     formUpdate : function(form, url, reset, callback){
13392         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
13393             if(typeof url == "function"){
13394                 url = url.call(this);
13395             }
13396             form = Roo.getDom(form);
13397             this.transaction = Roo.Ajax.request({
13398                 form: form,
13399                 url:url,
13400                 success: this.successDelegate,
13401                 failure: this.failureDelegate,
13402                 timeout: (this.timeout*1000),
13403                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
13404             });
13405             this.showLoading.defer(1, this);
13406         }
13407     },
13408
13409     /**
13410      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
13411      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
13412      */
13413     refresh : function(callback){
13414         if(this.defaultUrl == null){
13415             return;
13416         }
13417         this.update(this.defaultUrl, null, callback, true);
13418     },
13419
13420     /**
13421      * Set this element to auto refresh.
13422      * @param {Number} interval How often to update (in seconds).
13423      * @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)
13424      * @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}
13425      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
13426      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
13427      */
13428     startAutoRefresh : function(interval, url, params, callback, refreshNow){
13429         if(refreshNow){
13430             this.update(url || this.defaultUrl, params, callback, true);
13431         }
13432         if(this.autoRefreshProcId){
13433             clearInterval(this.autoRefreshProcId);
13434         }
13435         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
13436     },
13437
13438     /**
13439      * Stop auto refresh on this element.
13440      */
13441      stopAutoRefresh : function(){
13442         if(this.autoRefreshProcId){
13443             clearInterval(this.autoRefreshProcId);
13444             delete this.autoRefreshProcId;
13445         }
13446     },
13447
13448     isAutoRefreshing : function(){
13449        return this.autoRefreshProcId ? true : false;
13450     },
13451     /**
13452      * Called to update the element to "Loading" state. Override to perform custom action.
13453      */
13454     showLoading : function(){
13455         if(this.showLoadIndicator){
13456             this.el.update(this.indicatorText);
13457         }
13458     },
13459
13460     /**
13461      * Adds unique parameter to query string if disableCaching = true
13462      * @private
13463      */
13464     prepareUrl : function(url){
13465         if(this.disableCaching){
13466             var append = "_dc=" + (new Date().getTime());
13467             if(url.indexOf("?") !== -1){
13468                 url += "&" + append;
13469             }else{
13470                 url += "?" + append;
13471             }
13472         }
13473         return url;
13474     },
13475
13476     /**
13477      * @private
13478      */
13479     processSuccess : function(response){
13480         this.transaction = null;
13481         if(response.argument.form && response.argument.reset){
13482             try{ // put in try/catch since some older FF releases had problems with this
13483                 response.argument.form.reset();
13484             }catch(e){}
13485         }
13486         if(this.loadScripts){
13487             this.renderer.render(this.el, response, this,
13488                 this.updateComplete.createDelegate(this, [response]));
13489         }else{
13490             this.renderer.render(this.el, response, this);
13491             this.updateComplete(response);
13492         }
13493     },
13494
13495     updateComplete : function(response){
13496         this.fireEvent("update", this.el, response);
13497         if(typeof response.argument.callback == "function"){
13498             response.argument.callback(this.el, true, response);
13499         }
13500     },
13501
13502     /**
13503      * @private
13504      */
13505     processFailure : function(response){
13506         this.transaction = null;
13507         this.fireEvent("failure", this.el, response);
13508         if(typeof response.argument.callback == "function"){
13509             response.argument.callback(this.el, false, response);
13510         }
13511     },
13512
13513     /**
13514      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
13515      * @param {Object} renderer The object implementing the render() method
13516      */
13517     setRenderer : function(renderer){
13518         this.renderer = renderer;
13519     },
13520
13521     getRenderer : function(){
13522        return this.renderer;
13523     },
13524
13525     /**
13526      * Set the defaultUrl used for updates
13527      * @param {String/Function} defaultUrl The url or a function to call to get the url
13528      */
13529     setDefaultUrl : function(defaultUrl){
13530         this.defaultUrl = defaultUrl;
13531     },
13532
13533     /**
13534      * Aborts the executing transaction
13535      */
13536     abort : function(){
13537         if(this.transaction){
13538             Roo.Ajax.abort(this.transaction);
13539         }
13540     },
13541
13542     /**
13543      * Returns true if an update is in progress
13544      * @return {Boolean}
13545      */
13546     isUpdating : function(){
13547         if(this.transaction){
13548             return Roo.Ajax.isLoading(this.transaction);
13549         }
13550         return false;
13551     }
13552 });
13553
13554 /**
13555  * @class Roo.UpdateManager.defaults
13556  * @static (not really - but it helps the doc tool)
13557  * The defaults collection enables customizing the default properties of UpdateManager
13558  */
13559    Roo.UpdateManager.defaults = {
13560        /**
13561          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
13562          * @type Number
13563          */
13564          timeout : 30,
13565
13566          /**
13567          * True to process scripts by default (Defaults to false).
13568          * @type Boolean
13569          */
13570         loadScripts : false,
13571
13572         /**
13573         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
13574         * @type String
13575         */
13576         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
13577         /**
13578          * Whether to append unique parameter on get request to disable caching (Defaults to false).
13579          * @type Boolean
13580          */
13581         disableCaching : false,
13582         /**
13583          * Whether to show indicatorText when loading (Defaults to true).
13584          * @type Boolean
13585          */
13586         showLoadIndicator : true,
13587         /**
13588          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
13589          * @type String
13590          */
13591         indicatorText : '<div class="loading-indicator">Loading...</div>'
13592    };
13593
13594 /**
13595  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
13596  *Usage:
13597  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
13598  * @param {String/HTMLElement/Roo.Element} el The element to update
13599  * @param {String} url The url
13600  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
13601  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
13602  * @static
13603  * @deprecated
13604  * @member Roo.UpdateManager
13605  */
13606 Roo.UpdateManager.updateElement = function(el, url, params, options){
13607     var um = Roo.get(el, true).getUpdateManager();
13608     Roo.apply(um, options);
13609     um.update(url, params, options ? options.callback : null);
13610 };
13611 // alias for backwards compat
13612 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
13613 /**
13614  * @class Roo.UpdateManager.BasicRenderer
13615  * Default Content renderer. Updates the elements innerHTML with the responseText.
13616  */
13617 Roo.UpdateManager.BasicRenderer = function(){};
13618
13619 Roo.UpdateManager.BasicRenderer.prototype = {
13620     /**
13621      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
13622      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
13623      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
13624      * @param {Roo.Element} el The element being rendered
13625      * @param {Object} response The YUI Connect response object
13626      * @param {UpdateManager} updateManager The calling update manager
13627      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
13628      */
13629      render : function(el, response, updateManager, callback){
13630         el.update(response.responseText, updateManager.loadScripts, callback);
13631     }
13632 };
13633 /*
13634  * Based on:
13635  * Roo JS
13636  * (c)) Alan Knowles
13637  * Licence : LGPL
13638  */
13639
13640
13641 /**
13642  * @class Roo.DomTemplate
13643  * @extends Roo.Template
13644  * An effort at a dom based template engine..
13645  *
13646  * Similar to XTemplate, except it uses dom parsing to create the template..
13647  *
13648  * Supported features:
13649  *
13650  *  Tags:
13651
13652 <pre><code>
13653       {a_variable} - output encoded.
13654       {a_variable.format:("Y-m-d")} - call a method on the variable
13655       {a_variable:raw} - unencoded output
13656       {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
13657       {a_variable:this.method_on_template(...)} - call a method on the template object.
13658  
13659 </code></pre>
13660  *  The tpl tag:
13661 <pre><code>
13662         &lt;div roo-for="a_variable or condition.."&gt;&lt;/div&gt;
13663         &lt;div roo-if="a_variable or condition"&gt;&lt;/div&gt;
13664         &lt;div roo-exec="some javascript"&gt;&lt;/div&gt;
13665         &lt;div roo-name="named_template"&gt;&lt;/div&gt; 
13666   
13667 </code></pre>
13668  *      
13669  */
13670 Roo.DomTemplate = function()
13671 {
13672      Roo.DomTemplate.superclass.constructor.apply(this, arguments);
13673      if (this.html) {
13674         this.compile();
13675      }
13676 };
13677
13678
13679 Roo.extend(Roo.DomTemplate, Roo.Template, {
13680     /**
13681      * id counter for sub templates.
13682      */
13683     id : 0,
13684     /**
13685      * flag to indicate if dom parser is inside a pre,
13686      * it will strip whitespace if not.
13687      */
13688     inPre : false,
13689     
13690     /**
13691      * The various sub templates
13692      */
13693     tpls : false,
13694     
13695     
13696     
13697     /**
13698      *
13699      * basic tag replacing syntax
13700      * WORD:WORD()
13701      *
13702      * // you can fake an object call by doing this
13703      *  x.t:(test,tesT) 
13704      * 
13705      */
13706     re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
13707     //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
13708     
13709     iterChild : function (node, method) {
13710         
13711         var oldPre = this.inPre;
13712         if (node.tagName == 'PRE') {
13713             this.inPre = true;
13714         }
13715         for( var i = 0; i < node.childNodes.length; i++) {
13716             method.call(this, node.childNodes[i]);
13717         }
13718         this.inPre = oldPre;
13719     },
13720     
13721     
13722     
13723     /**
13724      * compile the template
13725      *
13726      * This is not recursive, so I'm not sure how nested templates are really going to be handled..
13727      *
13728      */
13729     compile: function()
13730     {
13731         var s = this.html;
13732         
13733         // covert the html into DOM...
13734         var doc = false;
13735         var div =false;
13736         try {
13737             doc = document.implementation.createHTMLDocument("");
13738             doc.documentElement.innerHTML =   this.html  ;
13739             div = doc.documentElement;
13740         } catch (e) {
13741             // old IE... - nasty -- it causes all sorts of issues.. with
13742             // images getting pulled from server..
13743             div = document.createElement('div');
13744             div.innerHTML = this.html;
13745         }
13746         //doc.documentElement.innerHTML = htmlBody
13747          
13748         
13749         
13750         this.tpls = [];
13751         var _t = this;
13752         this.iterChild(div, function(n) {_t.compileNode(n, true); });
13753         
13754         var tpls = this.tpls;
13755         
13756         // create a top level template from the snippet..
13757         
13758         //Roo.log(div.innerHTML);
13759         
13760         var tpl = {
13761             uid : 'master',
13762             id : this.id++,
13763             attr : false,
13764             value : false,
13765             body : div.innerHTML,
13766             
13767             forCall : false,
13768             execCall : false,
13769             dom : div,
13770             isTop : true
13771             
13772         };
13773         tpls.unshift(tpl);
13774         
13775         
13776         // compile them...
13777         this.tpls = [];
13778         Roo.each(tpls, function(tp){
13779             this.compileTpl(tp);
13780             this.tpls[tp.id] = tp;
13781         }, this);
13782         
13783         this.master = tpls[0];
13784         return this;
13785         
13786         
13787     },
13788     
13789     compileNode : function(node, istop) {
13790         // test for
13791         //Roo.log(node);
13792         
13793         
13794         // skip anything not a tag..
13795         if (node.nodeType != 1) {
13796             if (node.nodeType == 3 && !this.inPre) {
13797                 // reduce white space..
13798                 node.nodeValue = node.nodeValue.replace(/\s+/g, ' '); 
13799                 
13800             }
13801             return;
13802         }
13803         
13804         var tpl = {
13805             uid : false,
13806             id : false,
13807             attr : false,
13808             value : false,
13809             body : '',
13810             
13811             forCall : false,
13812             execCall : false,
13813             dom : false,
13814             isTop : istop
13815             
13816             
13817         };
13818         
13819         
13820         switch(true) {
13821             case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
13822             case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
13823             case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
13824             case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
13825             // no default..
13826         }
13827         
13828         
13829         if (!tpl.attr) {
13830             // just itterate children..
13831             this.iterChild(node,this.compileNode);
13832             return;
13833         }
13834         tpl.uid = this.id++;
13835         tpl.value = node.getAttribute('roo-' +  tpl.attr);
13836         node.removeAttribute('roo-'+ tpl.attr);
13837         if (tpl.attr != 'name') {
13838             var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
13839             node.parentNode.replaceChild(placeholder,  node);
13840         } else {
13841             
13842             var placeholder =  document.createElement('span');
13843             placeholder.className = 'roo-tpl-' + tpl.value;
13844             node.parentNode.replaceChild(placeholder,  node);
13845         }
13846         
13847         // parent now sees '{domtplXXXX}
13848         this.iterChild(node,this.compileNode);
13849         
13850         // we should now have node body...
13851         var div = document.createElement('div');
13852         div.appendChild(node);
13853         tpl.dom = node;
13854         // this has the unfortunate side effect of converting tagged attributes
13855         // eg. href="{...}" into %7C...%7D
13856         // this has been fixed by searching for those combo's although it's a bit hacky..
13857         
13858         
13859         tpl.body = div.innerHTML;
13860         
13861         
13862          
13863         tpl.id = tpl.uid;
13864         switch(tpl.attr) {
13865             case 'for' :
13866                 switch (tpl.value) {
13867                     case '.':  tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
13868                     case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
13869                     default:   tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
13870                 }
13871                 break;
13872             
13873             case 'exec':
13874                 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
13875                 break;
13876             
13877             case 'if':     
13878                 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
13879                 break;
13880             
13881             case 'name':
13882                 tpl.id  = tpl.value; // replace non characters???
13883                 break;
13884             
13885         }
13886         
13887         
13888         this.tpls.push(tpl);
13889         
13890         
13891         
13892     },
13893     
13894     
13895     
13896     
13897     /**
13898      * Compile a segment of the template into a 'sub-template'
13899      *
13900      * 
13901      * 
13902      *
13903      */
13904     compileTpl : function(tpl)
13905     {
13906         var fm = Roo.util.Format;
13907         var useF = this.disableFormats !== true;
13908         
13909         var sep = Roo.isGecko ? "+\n" : ",\n";
13910         
13911         var undef = function(str) {
13912             Roo.debug && Roo.log("Property not found :"  + str);
13913             return '';
13914         };
13915           
13916         //Roo.log(tpl.body);
13917         
13918         
13919         
13920         var fn = function(m, lbrace, name, format, args)
13921         {
13922             //Roo.log("ARGS");
13923             //Roo.log(arguments);
13924             args = args ? args.replace(/\\'/g,"'") : args;
13925             //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
13926             if (typeof(format) == 'undefined') {
13927                 format =  'htmlEncode'; 
13928             }
13929             if (format == 'raw' ) {
13930                 format = false;
13931             }
13932             
13933             if(name.substr(0, 6) == 'domtpl'){
13934                 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
13935             }
13936             
13937             // build an array of options to determine if value is undefined..
13938             
13939             // basically get 'xxxx.yyyy' then do
13940             // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
13941             //    (function () { Roo.log("Property not found"); return ''; })() :
13942             //    ......
13943             
13944             var udef_ar = [];
13945             var lookfor = '';
13946             Roo.each(name.split('.'), function(st) {
13947                 lookfor += (lookfor.length ? '.': '') + st;
13948                 udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
13949             });
13950             
13951             var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
13952             
13953             
13954             if(format && useF){
13955                 
13956                 args = args ? ',' + args : "";
13957                  
13958                 if(format.substr(0, 5) != "this."){
13959                     format = "fm." + format + '(';
13960                 }else{
13961                     format = 'this.call("'+ format.substr(5) + '", ';
13962                     args = ", values";
13963                 }
13964                 
13965                 return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
13966             }
13967              
13968             if (args && args.length) {
13969                 // called with xxyx.yuu:(test,test)
13970                 // change to ()
13971                 return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
13972             }
13973             // raw.. - :raw modifier..
13974             return "'"+ sep + udef_st  + name + ")"+sep+"'";
13975             
13976         };
13977         var body;
13978         // branched to use + in gecko and [].join() in others
13979         if(Roo.isGecko){
13980             body = "tpl.compiled = function(values, parent){  with(values) { return '" +
13981                    tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
13982                     "';};};";
13983         }else{
13984             body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
13985             body.push(tpl.body.replace(/(\r\n|\n)/g,
13986                             '\\n').replace(/'/g, "\\'").replace(this.re, fn));
13987             body.push("'].join('');};};");
13988             body = body.join('');
13989         }
13990         
13991         Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
13992        
13993         /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
13994         eval(body);
13995         
13996         return this;
13997     },
13998      
13999     /**
14000      * same as applyTemplate, except it's done to one of the subTemplates
14001      * when using named templates, you can do:
14002      *
14003      * var str = pl.applySubTemplate('your-name', values);
14004      *
14005      * 
14006      * @param {Number} id of the template
14007      * @param {Object} values to apply to template
14008      * @param {Object} parent (normaly the instance of this object)
14009      */
14010     applySubTemplate : function(id, values, parent)
14011     {
14012         
14013         
14014         var t = this.tpls[id];
14015         
14016         
14017         try { 
14018             if(t.ifCall && !t.ifCall.call(this, values, parent)){
14019                 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
14020                 return '';
14021             }
14022         } catch(e) {
14023             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
14024             Roo.log(values);
14025           
14026             return '';
14027         }
14028         try { 
14029             
14030             if(t.execCall && t.execCall.call(this, values, parent)){
14031                 return '';
14032             }
14033         } catch(e) {
14034             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
14035             Roo.log(values);
14036             return '';
14037         }
14038         
14039         try {
14040             var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
14041             parent = t.target ? values : parent;
14042             if(t.forCall && vs instanceof Array){
14043                 var buf = [];
14044                 for(var i = 0, len = vs.length; i < len; i++){
14045                     try {
14046                         buf[buf.length] = t.compiled.call(this, vs[i], parent);
14047                     } catch (e) {
14048                         Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
14049                         Roo.log(e.body);
14050                         //Roo.log(t.compiled);
14051                         Roo.log(vs[i]);
14052                     }   
14053                 }
14054                 return buf.join('');
14055             }
14056         } catch (e) {
14057             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
14058             Roo.log(values);
14059             return '';
14060         }
14061         try {
14062             return t.compiled.call(this, vs, parent);
14063         } catch (e) {
14064             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
14065             Roo.log(e.body);
14066             //Roo.log(t.compiled);
14067             Roo.log(values);
14068             return '';
14069         }
14070     },
14071
14072    
14073
14074     applyTemplate : function(values){
14075         return this.master.compiled.call(this, values, {});
14076         //var s = this.subs;
14077     },
14078
14079     apply : function(){
14080         return this.applyTemplate.apply(this, arguments);
14081     }
14082
14083  });
14084
14085 Roo.DomTemplate.from = function(el){
14086     el = Roo.getDom(el);
14087     return new Roo.Domtemplate(el.value || el.innerHTML);
14088 };/*
14089  * Based on:
14090  * Ext JS Library 1.1.1
14091  * Copyright(c) 2006-2007, Ext JS, LLC.
14092  *
14093  * Originally Released Under LGPL - original licence link has changed is not relivant.
14094  *
14095  * Fork - LGPL
14096  * <script type="text/javascript">
14097  */
14098
14099 /**
14100  * @class Roo.util.DelayedTask
14101  * Provides a convenient method of performing setTimeout where a new
14102  * timeout cancels the old timeout. An example would be performing validation on a keypress.
14103  * You can use this class to buffer
14104  * the keypress events for a certain number of milliseconds, and perform only if they stop
14105  * for that amount of time.
14106  * @constructor The parameters to this constructor serve as defaults and are not required.
14107  * @param {Function} fn (optional) The default function to timeout
14108  * @param {Object} scope (optional) The default scope of that timeout
14109  * @param {Array} args (optional) The default Array of arguments
14110  */
14111 Roo.util.DelayedTask = function(fn, scope, args){
14112     var id = null, d, t;
14113
14114     var call = function(){
14115         var now = new Date().getTime();
14116         if(now - t >= d){
14117             clearInterval(id);
14118             id = null;
14119             fn.apply(scope, args || []);
14120         }
14121     };
14122     /**
14123      * Cancels any pending timeout and queues a new one
14124      * @param {Number} delay The milliseconds to delay
14125      * @param {Function} newFn (optional) Overrides function passed to constructor
14126      * @param {Object} newScope (optional) Overrides scope passed to constructor
14127      * @param {Array} newArgs (optional) Overrides args passed to constructor
14128      */
14129     this.delay = function(delay, newFn, newScope, newArgs){
14130         if(id && delay != d){
14131             this.cancel();
14132         }
14133         d = delay;
14134         t = new Date().getTime();
14135         fn = newFn || fn;
14136         scope = newScope || scope;
14137         args = newArgs || args;
14138         if(!id){
14139             id = setInterval(call, d);
14140         }
14141     };
14142
14143     /**
14144      * Cancel the last queued timeout
14145      */
14146     this.cancel = function(){
14147         if(id){
14148             clearInterval(id);
14149             id = null;
14150         }
14151     };
14152 };/*
14153  * Based on:
14154  * Ext JS Library 1.1.1
14155  * Copyright(c) 2006-2007, Ext JS, LLC.
14156  *
14157  * Originally Released Under LGPL - original licence link has changed is not relivant.
14158  *
14159  * Fork - LGPL
14160  * <script type="text/javascript">
14161  */
14162 /**
14163  * @class Roo.util.TaskRunner
14164  * Manage background tasks - not sure why this is better that setInterval?
14165  * @static
14166  *
14167  */
14168  
14169 Roo.util.TaskRunner = function(interval){
14170     interval = interval || 10;
14171     var tasks = [], removeQueue = [];
14172     var id = 0;
14173     var running = false;
14174
14175     var stopThread = function(){
14176         running = false;
14177         clearInterval(id);
14178         id = 0;
14179     };
14180
14181     var startThread = function(){
14182         if(!running){
14183             running = true;
14184             id = setInterval(runTasks, interval);
14185         }
14186     };
14187
14188     var removeTask = function(task){
14189         removeQueue.push(task);
14190         if(task.onStop){
14191             task.onStop();
14192         }
14193     };
14194
14195     var runTasks = function(){
14196         if(removeQueue.length > 0){
14197             for(var i = 0, len = removeQueue.length; i < len; i++){
14198                 tasks.remove(removeQueue[i]);
14199             }
14200             removeQueue = [];
14201             if(tasks.length < 1){
14202                 stopThread();
14203                 return;
14204             }
14205         }
14206         var now = new Date().getTime();
14207         for(var i = 0, len = tasks.length; i < len; ++i){
14208             var t = tasks[i];
14209             var itime = now - t.taskRunTime;
14210             if(t.interval <= itime){
14211                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
14212                 t.taskRunTime = now;
14213                 if(rt === false || t.taskRunCount === t.repeat){
14214                     removeTask(t);
14215                     return;
14216                 }
14217             }
14218             if(t.duration && t.duration <= (now - t.taskStartTime)){
14219                 removeTask(t);
14220             }
14221         }
14222     };
14223
14224     /**
14225      * Queues a new task.
14226      * @param {Object} task
14227      *
14228      * Task property : interval = how frequent to run.
14229      * Task object should implement
14230      * function run()
14231      * Task object may implement
14232      * function onStop()
14233      */
14234     this.start = function(task){
14235         tasks.push(task);
14236         task.taskStartTime = new Date().getTime();
14237         task.taskRunTime = 0;
14238         task.taskRunCount = 0;
14239         startThread();
14240         return task;
14241     };
14242     /**
14243      * Stop  new task.
14244      * @param {Object} task
14245      */
14246     this.stop = function(task){
14247         removeTask(task);
14248         return task;
14249     };
14250     /**
14251      * Stop all Tasks
14252      */
14253     this.stopAll = function(){
14254         stopThread();
14255         for(var i = 0, len = tasks.length; i < len; i++){
14256             if(tasks[i].onStop){
14257                 tasks[i].onStop();
14258             }
14259         }
14260         tasks = [];
14261         removeQueue = [];
14262     };
14263 };
14264
14265 Roo.TaskMgr = new Roo.util.TaskRunner();/*
14266  * Based on:
14267  * Ext JS Library 1.1.1
14268  * Copyright(c) 2006-2007, Ext JS, LLC.
14269  *
14270  * Originally Released Under LGPL - original licence link has changed is not relivant.
14271  *
14272  * Fork - LGPL
14273  * <script type="text/javascript">
14274  */
14275
14276  
14277 /**
14278  * @class Roo.util.MixedCollection
14279  * @extends Roo.util.Observable
14280  * A Collection class that maintains both numeric indexes and keys and exposes events.
14281  * @constructor
14282  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
14283  * collection (defaults to false)
14284  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
14285  * and return the key value for that item.  This is used when available to look up the key on items that
14286  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
14287  * equivalent to providing an implementation for the {@link #getKey} method.
14288  */
14289 Roo.util.MixedCollection = function(allowFunctions, keyFn){
14290     this.items = [];
14291     this.map = {};
14292     this.keys = [];
14293     this.length = 0;
14294     this.addEvents({
14295         /**
14296          * @event clear
14297          * Fires when the collection is cleared.
14298          */
14299         "clear" : true,
14300         /**
14301          * @event add
14302          * Fires when an item is added to the collection.
14303          * @param {Number} index The index at which the item was added.
14304          * @param {Object} o The item added.
14305          * @param {String} key The key associated with the added item.
14306          */
14307         "add" : true,
14308         /**
14309          * @event replace
14310          * Fires when an item is replaced in the collection.
14311          * @param {String} key he key associated with the new added.
14312          * @param {Object} old The item being replaced.
14313          * @param {Object} new The new item.
14314          */
14315         "replace" : true,
14316         /**
14317          * @event remove
14318          * Fires when an item is removed from the collection.
14319          * @param {Object} o The item being removed.
14320          * @param {String} key (optional) The key associated with the removed item.
14321          */
14322         "remove" : true,
14323         "sort" : true
14324     });
14325     this.allowFunctions = allowFunctions === true;
14326     if(keyFn){
14327         this.getKey = keyFn;
14328     }
14329     Roo.util.MixedCollection.superclass.constructor.call(this);
14330 };
14331
14332 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
14333     allowFunctions : false,
14334     
14335 /**
14336  * Adds an item to the collection.
14337  * @param {String} key The key to associate with the item
14338  * @param {Object} o The item to add.
14339  * @return {Object} The item added.
14340  */
14341     add : function(key, o){
14342         if(arguments.length == 1){
14343             o = arguments[0];
14344             key = this.getKey(o);
14345         }
14346         if(typeof key == "undefined" || key === null){
14347             this.length++;
14348             this.items.push(o);
14349             this.keys.push(null);
14350         }else{
14351             var old = this.map[key];
14352             if(old){
14353                 return this.replace(key, o);
14354             }
14355             this.length++;
14356             this.items.push(o);
14357             this.map[key] = o;
14358             this.keys.push(key);
14359         }
14360         this.fireEvent("add", this.length-1, o, key);
14361         return o;
14362     },
14363        
14364 /**
14365   * MixedCollection has a generic way to fetch keys if you implement getKey.
14366 <pre><code>
14367 // normal way
14368 var mc = new Roo.util.MixedCollection();
14369 mc.add(someEl.dom.id, someEl);
14370 mc.add(otherEl.dom.id, otherEl);
14371 //and so on
14372
14373 // using getKey
14374 var mc = new Roo.util.MixedCollection();
14375 mc.getKey = function(el){
14376    return el.dom.id;
14377 };
14378 mc.add(someEl);
14379 mc.add(otherEl);
14380
14381 // or via the constructor
14382 var mc = new Roo.util.MixedCollection(false, function(el){
14383    return el.dom.id;
14384 });
14385 mc.add(someEl);
14386 mc.add(otherEl);
14387 </code></pre>
14388  * @param o {Object} The item for which to find the key.
14389  * @return {Object} The key for the passed item.
14390  */
14391     getKey : function(o){
14392          return o.id; 
14393     },
14394    
14395 /**
14396  * Replaces an item in the collection.
14397  * @param {String} key The key associated with the item to replace, or the item to replace.
14398  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
14399  * @return {Object}  The new item.
14400  */
14401     replace : function(key, o){
14402         if(arguments.length == 1){
14403             o = arguments[0];
14404             key = this.getKey(o);
14405         }
14406         var old = this.item(key);
14407         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
14408              return this.add(key, o);
14409         }
14410         var index = this.indexOfKey(key);
14411         this.items[index] = o;
14412         this.map[key] = o;
14413         this.fireEvent("replace", key, old, o);
14414         return o;
14415     },
14416    
14417 /**
14418  * Adds all elements of an Array or an Object to the collection.
14419  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
14420  * an Array of values, each of which are added to the collection.
14421  */
14422     addAll : function(objs){
14423         if(arguments.length > 1 || objs instanceof Array){
14424             var args = arguments.length > 1 ? arguments : objs;
14425             for(var i = 0, len = args.length; i < len; i++){
14426                 this.add(args[i]);
14427             }
14428         }else{
14429             for(var key in objs){
14430                 if(this.allowFunctions || typeof objs[key] != "function"){
14431                     this.add(key, objs[key]);
14432                 }
14433             }
14434         }
14435     },
14436    
14437 /**
14438  * Executes the specified function once for every item in the collection, passing each
14439  * item as the first and only parameter. returning false from the function will stop the iteration.
14440  * @param {Function} fn The function to execute for each item.
14441  * @param {Object} scope (optional) The scope in which to execute the function.
14442  */
14443     each : function(fn, scope){
14444         var items = [].concat(this.items); // each safe for removal
14445         for(var i = 0, len = items.length; i < len; i++){
14446             if(fn.call(scope || items[i], items[i], i, len) === false){
14447                 break;
14448             }
14449         }
14450     },
14451    
14452 /**
14453  * Executes the specified function once for every key in the collection, passing each
14454  * key, and its associated item as the first two parameters.
14455  * @param {Function} fn The function to execute for each item.
14456  * @param {Object} scope (optional) The scope in which to execute the function.
14457  */
14458     eachKey : function(fn, scope){
14459         for(var i = 0, len = this.keys.length; i < len; i++){
14460             fn.call(scope || window, this.keys[i], this.items[i], i, len);
14461         }
14462     },
14463    
14464 /**
14465  * Returns the first item in the collection which elicits a true return value from the
14466  * passed selection function.
14467  * @param {Function} fn The selection function to execute for each item.
14468  * @param {Object} scope (optional) The scope in which to execute the function.
14469  * @return {Object} The first item in the collection which returned true from the selection function.
14470  */
14471     find : function(fn, scope){
14472         for(var i = 0, len = this.items.length; i < len; i++){
14473             if(fn.call(scope || window, this.items[i], this.keys[i])){
14474                 return this.items[i];
14475             }
14476         }
14477         return null;
14478     },
14479    
14480 /**
14481  * Inserts an item at the specified index in the collection.
14482  * @param {Number} index The index to insert the item at.
14483  * @param {String} key The key to associate with the new item, or the item itself.
14484  * @param {Object} o  (optional) If the second parameter was a key, the new item.
14485  * @return {Object} The item inserted.
14486  */
14487     insert : function(index, key, o){
14488         if(arguments.length == 2){
14489             o = arguments[1];
14490             key = this.getKey(o);
14491         }
14492         if(index >= this.length){
14493             return this.add(key, o);
14494         }
14495         this.length++;
14496         this.items.splice(index, 0, o);
14497         if(typeof key != "undefined" && key != null){
14498             this.map[key] = o;
14499         }
14500         this.keys.splice(index, 0, key);
14501         this.fireEvent("add", index, o, key);
14502         return o;
14503     },
14504    
14505 /**
14506  * Removed an item from the collection.
14507  * @param {Object} o The item to remove.
14508  * @return {Object} The item removed.
14509  */
14510     remove : function(o){
14511         return this.removeAt(this.indexOf(o));
14512     },
14513    
14514 /**
14515  * Remove an item from a specified index in the collection.
14516  * @param {Number} index The index within the collection of the item to remove.
14517  */
14518     removeAt : function(index){
14519         if(index < this.length && index >= 0){
14520             this.length--;
14521             var o = this.items[index];
14522             this.items.splice(index, 1);
14523             var key = this.keys[index];
14524             if(typeof key != "undefined"){
14525                 delete this.map[key];
14526             }
14527             this.keys.splice(index, 1);
14528             this.fireEvent("remove", o, key);
14529         }
14530     },
14531    
14532 /**
14533  * Removed an item associated with the passed key fom the collection.
14534  * @param {String} key The key of the item to remove.
14535  */
14536     removeKey : function(key){
14537         return this.removeAt(this.indexOfKey(key));
14538     },
14539    
14540 /**
14541  * Returns the number of items in the collection.
14542  * @return {Number} the number of items in the collection.
14543  */
14544     getCount : function(){
14545         return this.length; 
14546     },
14547    
14548 /**
14549  * Returns index within the collection of the passed Object.
14550  * @param {Object} o The item to find the index of.
14551  * @return {Number} index of the item.
14552  */
14553     indexOf : function(o){
14554         if(!this.items.indexOf){
14555             for(var i = 0, len = this.items.length; i < len; i++){
14556                 if(this.items[i] == o) {
14557                     return i;
14558                 }
14559             }
14560             return -1;
14561         }else{
14562             return this.items.indexOf(o);
14563         }
14564     },
14565    
14566 /**
14567  * Returns index within the collection of the passed key.
14568  * @param {String} key The key to find the index of.
14569  * @return {Number} index of the key.
14570  */
14571     indexOfKey : function(key){
14572         if(!this.keys.indexOf){
14573             for(var i = 0, len = this.keys.length; i < len; i++){
14574                 if(this.keys[i] == key) {
14575                     return i;
14576                 }
14577             }
14578             return -1;
14579         }else{
14580             return this.keys.indexOf(key);
14581         }
14582     },
14583    
14584 /**
14585  * Returns the item associated with the passed key OR index. Key has priority over index.
14586  * @param {String/Number} key The key or index of the item.
14587  * @return {Object} The item associated with the passed key.
14588  */
14589     item : function(key){
14590         if (key === 'length') {
14591             return null;
14592         }
14593         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
14594         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
14595     },
14596     
14597 /**
14598  * Returns the item at the specified index.
14599  * @param {Number} index The index of the item.
14600  * @return {Object}
14601  */
14602     itemAt : function(index){
14603         return this.items[index];
14604     },
14605     
14606 /**
14607  * Returns the item associated with the passed key.
14608  * @param {String/Number} key The key of the item.
14609  * @return {Object} The item associated with the passed key.
14610  */
14611     key : function(key){
14612         return this.map[key];
14613     },
14614    
14615 /**
14616  * Returns true if the collection contains the passed Object as an item.
14617  * @param {Object} o  The Object to look for in the collection.
14618  * @return {Boolean} True if the collection contains the Object as an item.
14619  */
14620     contains : function(o){
14621         return this.indexOf(o) != -1;
14622     },
14623    
14624 /**
14625  * Returns true if the collection contains the passed Object as a key.
14626  * @param {String} key The key to look for in the collection.
14627  * @return {Boolean} True if the collection contains the Object as a key.
14628  */
14629     containsKey : function(key){
14630         return typeof this.map[key] != "undefined";
14631     },
14632    
14633 /**
14634  * Removes all items from the collection.
14635  */
14636     clear : function(){
14637         this.length = 0;
14638         this.items = [];
14639         this.keys = [];
14640         this.map = {};
14641         this.fireEvent("clear");
14642     },
14643    
14644 /**
14645  * Returns the first item in the collection.
14646  * @return {Object} the first item in the collection..
14647  */
14648     first : function(){
14649         return this.items[0]; 
14650     },
14651    
14652 /**
14653  * Returns the last item in the collection.
14654  * @return {Object} the last item in the collection..
14655  */
14656     last : function(){
14657         return this.items[this.length-1];   
14658     },
14659     
14660     _sort : function(property, dir, fn){
14661         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
14662         fn = fn || function(a, b){
14663             return a-b;
14664         };
14665         var c = [], k = this.keys, items = this.items;
14666         for(var i = 0, len = items.length; i < len; i++){
14667             c[c.length] = {key: k[i], value: items[i], index: i};
14668         }
14669         c.sort(function(a, b){
14670             var v = fn(a[property], b[property]) * dsc;
14671             if(v == 0){
14672                 v = (a.index < b.index ? -1 : 1);
14673             }
14674             return v;
14675         });
14676         for(var i = 0, len = c.length; i < len; i++){
14677             items[i] = c[i].value;
14678             k[i] = c[i].key;
14679         }
14680         this.fireEvent("sort", this);
14681     },
14682     
14683     /**
14684      * Sorts this collection with the passed comparison function
14685      * @param {String} direction (optional) "ASC" or "DESC"
14686      * @param {Function} fn (optional) comparison function
14687      */
14688     sort : function(dir, fn){
14689         this._sort("value", dir, fn);
14690     },
14691     
14692     /**
14693      * Sorts this collection by keys
14694      * @param {String} direction (optional) "ASC" or "DESC"
14695      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
14696      */
14697     keySort : function(dir, fn){
14698         this._sort("key", dir, fn || function(a, b){
14699             return String(a).toUpperCase()-String(b).toUpperCase();
14700         });
14701     },
14702     
14703     /**
14704      * Returns a range of items in this collection
14705      * @param {Number} startIndex (optional) defaults to 0
14706      * @param {Number} endIndex (optional) default to the last item
14707      * @return {Array} An array of items
14708      */
14709     getRange : function(start, end){
14710         var items = this.items;
14711         if(items.length < 1){
14712             return [];
14713         }
14714         start = start || 0;
14715         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
14716         var r = [];
14717         if(start <= end){
14718             for(var i = start; i <= end; i++) {
14719                     r[r.length] = items[i];
14720             }
14721         }else{
14722             for(var i = start; i >= end; i--) {
14723                     r[r.length] = items[i];
14724             }
14725         }
14726         return r;
14727     },
14728         
14729     /**
14730      * Filter the <i>objects</i> in this collection by a specific property. 
14731      * Returns a new collection that has been filtered.
14732      * @param {String} property A property on your objects
14733      * @param {String/RegExp} value Either string that the property values 
14734      * should start with or a RegExp to test against the property
14735      * @return {MixedCollection} The new filtered collection
14736      */
14737     filter : function(property, value){
14738         if(!value.exec){ // not a regex
14739             value = String(value);
14740             if(value.length == 0){
14741                 return this.clone();
14742             }
14743             value = new RegExp("^" + Roo.escapeRe(value), "i");
14744         }
14745         return this.filterBy(function(o){
14746             return o && value.test(o[property]);
14747         });
14748         },
14749     
14750     /**
14751      * Filter by a function. * Returns a new collection that has been filtered.
14752      * The passed function will be called with each 
14753      * object in the collection. If the function returns true, the value is included 
14754      * otherwise it is filtered.
14755      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
14756      * @param {Object} scope (optional) The scope of the function (defaults to this) 
14757      * @return {MixedCollection} The new filtered collection
14758      */
14759     filterBy : function(fn, scope){
14760         var r = new Roo.util.MixedCollection();
14761         r.getKey = this.getKey;
14762         var k = this.keys, it = this.items;
14763         for(var i = 0, len = it.length; i < len; i++){
14764             if(fn.call(scope||this, it[i], k[i])){
14765                                 r.add(k[i], it[i]);
14766                         }
14767         }
14768         return r;
14769     },
14770     
14771     /**
14772      * Creates a duplicate of this collection
14773      * @return {MixedCollection}
14774      */
14775     clone : function(){
14776         var r = new Roo.util.MixedCollection();
14777         var k = this.keys, it = this.items;
14778         for(var i = 0, len = it.length; i < len; i++){
14779             r.add(k[i], it[i]);
14780         }
14781         r.getKey = this.getKey;
14782         return r;
14783     }
14784 });
14785 /**
14786  * Returns the item associated with the passed key or index.
14787  * @method
14788  * @param {String/Number} key The key or index of the item.
14789  * @return {Object} The item associated with the passed key.
14790  */
14791 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
14792  * Based on:
14793  * Ext JS Library 1.1.1
14794  * Copyright(c) 2006-2007, Ext JS, LLC.
14795  *
14796  * Originally Released Under LGPL - original licence link has changed is not relivant.
14797  *
14798  * Fork - LGPL
14799  * <script type="text/javascript">
14800  */
14801 /**
14802  * @class Roo.util.JSON
14803  * Modified version of Douglas Crockford"s json.js that doesn"t
14804  * mess with the Object prototype 
14805  * http://www.json.org/js.html
14806  * @static
14807  */
14808 Roo.util.JSON = new (function(){
14809     var useHasOwn = {}.hasOwnProperty ? true : false;
14810     
14811     // crashes Safari in some instances
14812     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
14813     
14814     var pad = function(n) {
14815         return n < 10 ? "0" + n : n;
14816     };
14817     
14818     var m = {
14819         "\b": '\\b',
14820         "\t": '\\t',
14821         "\n": '\\n',
14822         "\f": '\\f',
14823         "\r": '\\r',
14824         '"' : '\\"',
14825         "\\": '\\\\'
14826     };
14827
14828     var encodeString = function(s){
14829         if (/["\\\x00-\x1f]/.test(s)) {
14830             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
14831                 var c = m[b];
14832                 if(c){
14833                     return c;
14834                 }
14835                 c = b.charCodeAt();
14836                 return "\\u00" +
14837                     Math.floor(c / 16).toString(16) +
14838                     (c % 16).toString(16);
14839             }) + '"';
14840         }
14841         return '"' + s + '"';
14842     };
14843     
14844     var encodeArray = function(o){
14845         var a = ["["], b, i, l = o.length, v;
14846             for (i = 0; i < l; i += 1) {
14847                 v = o[i];
14848                 switch (typeof v) {
14849                     case "undefined":
14850                     case "function":
14851                     case "unknown":
14852                         break;
14853                     default:
14854                         if (b) {
14855                             a.push(',');
14856                         }
14857                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
14858                         b = true;
14859                 }
14860             }
14861             a.push("]");
14862             return a.join("");
14863     };
14864     
14865     var encodeDate = function(o){
14866         return '"' + o.getFullYear() + "-" +
14867                 pad(o.getMonth() + 1) + "-" +
14868                 pad(o.getDate()) + "T" +
14869                 pad(o.getHours()) + ":" +
14870                 pad(o.getMinutes()) + ":" +
14871                 pad(o.getSeconds()) + '"';
14872     };
14873     
14874     /**
14875      * Encodes an Object, Array or other value
14876      * @param {Mixed} o The variable to encode
14877      * @return {String} The JSON string
14878      */
14879     this.encode = function(o)
14880     {
14881         // should this be extended to fully wrap stringify..
14882         
14883         if(typeof o == "undefined" || o === null){
14884             return "null";
14885         }else if(o instanceof Array){
14886             return encodeArray(o);
14887         }else if(o instanceof Date){
14888             return encodeDate(o);
14889         }else if(typeof o == "string"){
14890             return encodeString(o);
14891         }else if(typeof o == "number"){
14892             return isFinite(o) ? String(o) : "null";
14893         }else if(typeof o == "boolean"){
14894             return String(o);
14895         }else {
14896             var a = ["{"], b, i, v;
14897             for (i in o) {
14898                 if(!useHasOwn || o.hasOwnProperty(i)) {
14899                     v = o[i];
14900                     switch (typeof v) {
14901                     case "undefined":
14902                     case "function":
14903                     case "unknown":
14904                         break;
14905                     default:
14906                         if(b){
14907                             a.push(',');
14908                         }
14909                         a.push(this.encode(i), ":",
14910                                 v === null ? "null" : this.encode(v));
14911                         b = true;
14912                     }
14913                 }
14914             }
14915             a.push("}");
14916             return a.join("");
14917         }
14918     };
14919     
14920     /**
14921      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
14922      * @param {String} json The JSON string
14923      * @return {Object} The resulting object
14924      */
14925     this.decode = function(json){
14926         
14927         return  /** eval:var:json */ eval("(" + json + ')');
14928     };
14929 })();
14930 /** 
14931  * Shorthand for {@link Roo.util.JSON#encode}
14932  * @member Roo encode 
14933  * @method */
14934 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
14935 /** 
14936  * Shorthand for {@link Roo.util.JSON#decode}
14937  * @member Roo decode 
14938  * @method */
14939 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
14940 /*
14941  * Based on:
14942  * Ext JS Library 1.1.1
14943  * Copyright(c) 2006-2007, Ext JS, LLC.
14944  *
14945  * Originally Released Under LGPL - original licence link has changed is not relivant.
14946  *
14947  * Fork - LGPL
14948  * <script type="text/javascript">
14949  */
14950  
14951 /**
14952  * @class Roo.util.Format
14953  * Reusable data formatting functions
14954  * @static
14955  */
14956 Roo.util.Format = function(){
14957     var trimRe = /^\s+|\s+$/g;
14958     return {
14959         /**
14960          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
14961          * @param {String} value The string to truncate
14962          * @param {Number} length The maximum length to allow before truncating
14963          * @return {String} The converted text
14964          */
14965         ellipsis : function(value, len){
14966             if(value && value.length > len){
14967                 return value.substr(0, len-3)+"...";
14968             }
14969             return value;
14970         },
14971
14972         /**
14973          * Checks a reference and converts it to empty string if it is undefined
14974          * @param {Mixed} value Reference to check
14975          * @return {Mixed} Empty string if converted, otherwise the original value
14976          */
14977         undef : function(value){
14978             return typeof value != "undefined" ? value : "";
14979         },
14980
14981         /**
14982          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
14983          * @param {String} value The string to encode
14984          * @return {String} The encoded text
14985          */
14986         htmlEncode : function(value){
14987             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
14988         },
14989
14990         /**
14991          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
14992          * @param {String} value The string to decode
14993          * @return {String} The decoded text
14994          */
14995         htmlDecode : function(value){
14996             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
14997         },
14998
14999         /**
15000          * Trims any whitespace from either side of a string
15001          * @param {String} value The text to trim
15002          * @return {String} The trimmed text
15003          */
15004         trim : function(value){
15005             return String(value).replace(trimRe, "");
15006         },
15007
15008         /**
15009          * Returns a substring from within an original string
15010          * @param {String} value The original text
15011          * @param {Number} start The start index of the substring
15012          * @param {Number} length The length of the substring
15013          * @return {String} The substring
15014          */
15015         substr : function(value, start, length){
15016             return String(value).substr(start, length);
15017         },
15018
15019         /**
15020          * Converts a string to all lower case letters
15021          * @param {String} value The text to convert
15022          * @return {String} The converted text
15023          */
15024         lowercase : function(value){
15025             return String(value).toLowerCase();
15026         },
15027
15028         /**
15029          * Converts a string to all upper case letters
15030          * @param {String} value The text to convert
15031          * @return {String} The converted text
15032          */
15033         uppercase : function(value){
15034             return String(value).toUpperCase();
15035         },
15036
15037         /**
15038          * Converts the first character only of a string to upper case
15039          * @param {String} value The text to convert
15040          * @return {String} The converted text
15041          */
15042         capitalize : function(value){
15043             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
15044         },
15045
15046         // private
15047         call : function(value, fn){
15048             if(arguments.length > 2){
15049                 var args = Array.prototype.slice.call(arguments, 2);
15050                 args.unshift(value);
15051                  
15052                 return /** eval:var:value */  eval(fn).apply(window, args);
15053             }else{
15054                 /** eval:var:value */
15055                 return /** eval:var:value */ eval(fn).call(window, value);
15056             }
15057         },
15058
15059        
15060         /**
15061          * safer version of Math.toFixed..??/
15062          * @param {Number/String} value The numeric value to format
15063          * @param {Number/String} value Decimal places 
15064          * @return {String} The formatted currency string
15065          */
15066         toFixed : function(v, n)
15067         {
15068             // why not use to fixed - precision is buggered???
15069             if (!n) {
15070                 return Math.round(v-0);
15071             }
15072             var fact = Math.pow(10,n+1);
15073             v = (Math.round((v-0)*fact))/fact;
15074             var z = (''+fact).substring(2);
15075             if (v == Math.floor(v)) {
15076                 return Math.floor(v) + '.' + z;
15077             }
15078             
15079             // now just padd decimals..
15080             var ps = String(v).split('.');
15081             var fd = (ps[1] + z);
15082             var r = fd.substring(0,n); 
15083             var rm = fd.substring(n); 
15084             if (rm < 5) {
15085                 return ps[0] + '.' + r;
15086             }
15087             r*=1; // turn it into a number;
15088             r++;
15089             if (String(r).length != n) {
15090                 ps[0]*=1;
15091                 ps[0]++;
15092                 r = String(r).substring(1); // chop the end off.
15093             }
15094             
15095             return ps[0] + '.' + r;
15096              
15097         },
15098         
15099         /**
15100          * Format a number as US currency
15101          * @param {Number/String} value The numeric value to format
15102          * @return {String} The formatted currency string
15103          */
15104         usMoney : function(v){
15105             return '$' + Roo.util.Format.number(v);
15106         },
15107         
15108         /**
15109          * Format a number
15110          * eventually this should probably emulate php's number_format
15111          * @param {Number/String} value The numeric value to format
15112          * @param {Number} decimals number of decimal places
15113          * @param {String} delimiter for thousands (default comma)
15114          * @return {String} The formatted currency string
15115          */
15116         number : function(v, decimals, thousandsDelimiter)
15117         {
15118             // multiply and round.
15119             decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
15120             thousandsDelimiter = typeof(thousandsDelimiter) == 'undefined' ? ',' : thousandsDelimiter;
15121             
15122             var mul = Math.pow(10, decimals);
15123             var zero = String(mul).substring(1);
15124             v = (Math.round((v-0)*mul))/mul;
15125             
15126             // if it's '0' number.. then
15127             
15128             //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
15129             v = String(v);
15130             var ps = v.split('.');
15131             var whole = ps[0];
15132             
15133             var r = /(\d+)(\d{3})/;
15134             // add comma's
15135             
15136             if(thousandsDelimiter.length != 0) {
15137                 whole = whole.replace(/\B(?=(\d{3})+(?!\d))/g, thousandsDelimiter );
15138             } 
15139             
15140             var sub = ps[1] ?
15141                     // has decimals..
15142                     (decimals ?  ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
15143                     // does not have decimals
15144                     (decimals ? ('.' + zero) : '');
15145             
15146             
15147             return whole + sub ;
15148         },
15149         
15150         /**
15151          * Parse a value into a formatted date using the specified format pattern.
15152          * @param {Mixed} value The value to format
15153          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
15154          * @return {String} The formatted date string
15155          */
15156         date : function(v, format){
15157             if(!v){
15158                 return "";
15159             }
15160             if(!(v instanceof Date)){
15161                 v = new Date(Date.parse(v));
15162             }
15163             return v.dateFormat(format || Roo.util.Format.defaults.date);
15164         },
15165
15166         /**
15167          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
15168          * @param {String} format Any valid date format string
15169          * @return {Function} The date formatting function
15170          */
15171         dateRenderer : function(format){
15172             return function(v){
15173                 return Roo.util.Format.date(v, format);  
15174             };
15175         },
15176
15177         // private
15178         stripTagsRE : /<\/?[^>]+>/gi,
15179         
15180         /**
15181          * Strips all HTML tags
15182          * @param {Mixed} value The text from which to strip tags
15183          * @return {String} The stripped text
15184          */
15185         stripTags : function(v){
15186             return !v ? v : String(v).replace(this.stripTagsRE, "");
15187         },
15188         
15189         /**
15190          * Size in Mb,Gb etc.
15191          * @param {Number} value The number to be formated
15192          * @param {number} decimals how many decimal places
15193          * @return {String} the formated string
15194          */
15195         size : function(value, decimals)
15196         {
15197             var sizes = ['b', 'k', 'M', 'G', 'T'];
15198             if (value == 0) {
15199                 return 0;
15200             }
15201             var i = parseInt(Math.floor(Math.log(value) / Math.log(1024)));
15202             return Roo.util.Format.number(value/ Math.pow(1024, i) ,decimals)   + sizes[i];
15203         }
15204         
15205         
15206         
15207     };
15208 }();
15209 Roo.util.Format.defaults = {
15210     date : 'd/M/Y'
15211 };/*
15212  * Based on:
15213  * Ext JS Library 1.1.1
15214  * Copyright(c) 2006-2007, Ext JS, LLC.
15215  *
15216  * Originally Released Under LGPL - original licence link has changed is not relivant.
15217  *
15218  * Fork - LGPL
15219  * <script type="text/javascript">
15220  */
15221
15222
15223  
15224
15225 /**
15226  * @class Roo.MasterTemplate
15227  * @extends Roo.Template
15228  * Provides a template that can have child templates. The syntax is:
15229 <pre><code>
15230 var t = new Roo.MasterTemplate(
15231         '&lt;select name="{name}"&gt;',
15232                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
15233         '&lt;/select&gt;'
15234 );
15235 t.add('options', {value: 'foo', text: 'bar'});
15236 // or you can add multiple child elements in one shot
15237 t.addAll('options', [
15238     {value: 'foo', text: 'bar'},
15239     {value: 'foo2', text: 'bar2'},
15240     {value: 'foo3', text: 'bar3'}
15241 ]);
15242 // then append, applying the master template values
15243 t.append('my-form', {name: 'my-select'});
15244 </code></pre>
15245 * A name attribute for the child template is not required if you have only one child
15246 * template or you want to refer to them by index.
15247  */
15248 Roo.MasterTemplate = function(){
15249     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
15250     this.originalHtml = this.html;
15251     var st = {};
15252     var m, re = this.subTemplateRe;
15253     re.lastIndex = 0;
15254     var subIndex = 0;
15255     while(m = re.exec(this.html)){
15256         var name = m[1], content = m[2];
15257         st[subIndex] = {
15258             name: name,
15259             index: subIndex,
15260             buffer: [],
15261             tpl : new Roo.Template(content)
15262         };
15263         if(name){
15264             st[name] = st[subIndex];
15265         }
15266         st[subIndex].tpl.compile();
15267         st[subIndex].tpl.call = this.call.createDelegate(this);
15268         subIndex++;
15269     }
15270     this.subCount = subIndex;
15271     this.subs = st;
15272 };
15273 Roo.extend(Roo.MasterTemplate, Roo.Template, {
15274     /**
15275     * The regular expression used to match sub templates
15276     * @type RegExp
15277     * @property
15278     */
15279     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
15280
15281     /**
15282      * Applies the passed values to a child template.
15283      * @param {String/Number} name (optional) The name or index of the child template
15284      * @param {Array/Object} values The values to be applied to the template
15285      * @return {MasterTemplate} this
15286      */
15287      add : function(name, values){
15288         if(arguments.length == 1){
15289             values = arguments[0];
15290             name = 0;
15291         }
15292         var s = this.subs[name];
15293         s.buffer[s.buffer.length] = s.tpl.apply(values);
15294         return this;
15295     },
15296
15297     /**
15298      * Applies all the passed values to a child template.
15299      * @param {String/Number} name (optional) The name or index of the child template
15300      * @param {Array} values The values to be applied to the template, this should be an array of objects.
15301      * @param {Boolean} reset (optional) True to reset the template first
15302      * @return {MasterTemplate} this
15303      */
15304     fill : function(name, values, reset){
15305         var a = arguments;
15306         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
15307             values = a[0];
15308             name = 0;
15309             reset = a[1];
15310         }
15311         if(reset){
15312             this.reset();
15313         }
15314         for(var i = 0, len = values.length; i < len; i++){
15315             this.add(name, values[i]);
15316         }
15317         return this;
15318     },
15319
15320     /**
15321      * Resets the template for reuse
15322      * @return {MasterTemplate} this
15323      */
15324      reset : function(){
15325         var s = this.subs;
15326         for(var i = 0; i < this.subCount; i++){
15327             s[i].buffer = [];
15328         }
15329         return this;
15330     },
15331
15332     applyTemplate : function(values){
15333         var s = this.subs;
15334         var replaceIndex = -1;
15335         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
15336             return s[++replaceIndex].buffer.join("");
15337         });
15338         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
15339     },
15340
15341     apply : function(){
15342         return this.applyTemplate.apply(this, arguments);
15343     },
15344
15345     compile : function(){return this;}
15346 });
15347
15348 /**
15349  * Alias for fill().
15350  * @method
15351  */
15352 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
15353  /**
15354  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
15355  * var tpl = Roo.MasterTemplate.from('element-id');
15356  * @param {String/HTMLElement} el
15357  * @param {Object} config
15358  * @static
15359  */
15360 Roo.MasterTemplate.from = function(el, config){
15361     el = Roo.getDom(el);
15362     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
15363 };/*
15364  * Based on:
15365  * Ext JS Library 1.1.1
15366  * Copyright(c) 2006-2007, Ext JS, LLC.
15367  *
15368  * Originally Released Under LGPL - original licence link has changed is not relivant.
15369  *
15370  * Fork - LGPL
15371  * <script type="text/javascript">
15372  */
15373
15374  
15375 /**
15376  * @class Roo.util.CSS
15377  * Utility class for manipulating CSS rules
15378  * @static
15379
15380  */
15381 Roo.util.CSS = function(){
15382         var rules = null;
15383         var doc = document;
15384
15385     var camelRe = /(-[a-z])/gi;
15386     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
15387
15388    return {
15389    /**
15390     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
15391     * tag and appended to the HEAD of the document.
15392     * @param {String|Object} cssText The text containing the css rules
15393     * @param {String} id An id to add to the stylesheet for later removal
15394     * @return {StyleSheet}
15395     */
15396     createStyleSheet : function(cssText, id){
15397         var ss;
15398         var head = doc.getElementsByTagName("head")[0];
15399         var nrules = doc.createElement("style");
15400         nrules.setAttribute("type", "text/css");
15401         if(id){
15402             nrules.setAttribute("id", id);
15403         }
15404         if (typeof(cssText) != 'string') {
15405             // support object maps..
15406             // not sure if this a good idea.. 
15407             // perhaps it should be merged with the general css handling
15408             // and handle js style props.
15409             var cssTextNew = [];
15410             for(var n in cssText) {
15411                 var citems = [];
15412                 for(var k in cssText[n]) {
15413                     citems.push( k + ' : ' +cssText[n][k] + ';' );
15414                 }
15415                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
15416                 
15417             }
15418             cssText = cssTextNew.join("\n");
15419             
15420         }
15421        
15422        
15423        if(Roo.isIE){
15424            head.appendChild(nrules);
15425            ss = nrules.styleSheet;
15426            ss.cssText = cssText;
15427        }else{
15428            try{
15429                 nrules.appendChild(doc.createTextNode(cssText));
15430            }catch(e){
15431                nrules.cssText = cssText; 
15432            }
15433            head.appendChild(nrules);
15434            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
15435        }
15436        this.cacheStyleSheet(ss);
15437        return ss;
15438    },
15439
15440    /**
15441     * Removes a style or link tag by id
15442     * @param {String} id The id of the tag
15443     */
15444    removeStyleSheet : function(id){
15445        var existing = doc.getElementById(id);
15446        if(existing){
15447            existing.parentNode.removeChild(existing);
15448        }
15449    },
15450
15451    /**
15452     * Dynamically swaps an existing stylesheet reference for a new one
15453     * @param {String} id The id of an existing link tag to remove
15454     * @param {String} url The href of the new stylesheet to include
15455     */
15456    swapStyleSheet : function(id, url){
15457        this.removeStyleSheet(id);
15458        var ss = doc.createElement("link");
15459        ss.setAttribute("rel", "stylesheet");
15460        ss.setAttribute("type", "text/css");
15461        ss.setAttribute("id", id);
15462        ss.setAttribute("href", url);
15463        doc.getElementsByTagName("head")[0].appendChild(ss);
15464    },
15465    
15466    /**
15467     * Refresh the rule cache if you have dynamically added stylesheets
15468     * @return {Object} An object (hash) of rules indexed by selector
15469     */
15470    refreshCache : function(){
15471        return this.getRules(true);
15472    },
15473
15474    // private
15475    cacheStyleSheet : function(stylesheet){
15476        if(!rules){
15477            rules = {};
15478        }
15479        try{// try catch for cross domain access issue
15480            var ssRules = stylesheet.cssRules || stylesheet.rules;
15481            for(var j = ssRules.length-1; j >= 0; --j){
15482                rules[ssRules[j].selectorText] = ssRules[j];
15483            }
15484        }catch(e){}
15485    },
15486    
15487    /**
15488     * Gets all css rules for the document
15489     * @param {Boolean} refreshCache true to refresh the internal cache
15490     * @return {Object} An object (hash) of rules indexed by selector
15491     */
15492    getRules : function(refreshCache){
15493                 if(rules == null || refreshCache){
15494                         rules = {};
15495                         var ds = doc.styleSheets;
15496                         for(var i =0, len = ds.length; i < len; i++){
15497                             try{
15498                         this.cacheStyleSheet(ds[i]);
15499                     }catch(e){} 
15500                 }
15501                 }
15502                 return rules;
15503         },
15504         
15505         /**
15506     * Gets an an individual CSS rule by selector(s)
15507     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
15508     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
15509     * @return {CSSRule} The CSS rule or null if one is not found
15510     */
15511    getRule : function(selector, refreshCache){
15512                 var rs = this.getRules(refreshCache);
15513                 if(!(selector instanceof Array)){
15514                     return rs[selector];
15515                 }
15516                 for(var i = 0; i < selector.length; i++){
15517                         if(rs[selector[i]]){
15518                                 return rs[selector[i]];
15519                         }
15520                 }
15521                 return null;
15522         },
15523         
15524         
15525         /**
15526     * Updates a rule property
15527     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
15528     * @param {String} property The css property
15529     * @param {String} value The new value for the property
15530     * @return {Boolean} true If a rule was found and updated
15531     */
15532    updateRule : function(selector, property, value){
15533                 if(!(selector instanceof Array)){
15534                         var rule = this.getRule(selector);
15535                         if(rule){
15536                                 rule.style[property.replace(camelRe, camelFn)] = value;
15537                                 return true;
15538                         }
15539                 }else{
15540                         for(var i = 0; i < selector.length; i++){
15541                                 if(this.updateRule(selector[i], property, value)){
15542                                         return true;
15543                                 }
15544                         }
15545                 }
15546                 return false;
15547         }
15548    };   
15549 }();/*
15550  * Based on:
15551  * Ext JS Library 1.1.1
15552  * Copyright(c) 2006-2007, Ext JS, LLC.
15553  *
15554  * Originally Released Under LGPL - original licence link has changed is not relivant.
15555  *
15556  * Fork - LGPL
15557  * <script type="text/javascript">
15558  */
15559
15560  
15561
15562 /**
15563  * @class Roo.util.ClickRepeater
15564  * @extends Roo.util.Observable
15565  * 
15566  * A wrapper class which can be applied to any element. Fires a "click" event while the
15567  * mouse is pressed. The interval between firings may be specified in the config but
15568  * defaults to 10 milliseconds.
15569  * 
15570  * Optionally, a CSS class may be applied to the element during the time it is pressed.
15571  * 
15572  * @cfg {String/HTMLElement/Element} el The element to act as a button.
15573  * @cfg {Number} delay The initial delay before the repeating event begins firing.
15574  * Similar to an autorepeat key delay.
15575  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
15576  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
15577  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
15578  *           "interval" and "delay" are ignored. "immediate" is honored.
15579  * @cfg {Boolean} preventDefault True to prevent the default click event
15580  * @cfg {Boolean} stopDefault True to stop the default click event
15581  * 
15582  * @history
15583  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
15584  *     2007-02-02 jvs Renamed to ClickRepeater
15585  *   2007-02-03 jvs Modifications for FF Mac and Safari 
15586  *
15587  *  @constructor
15588  * @param {String/HTMLElement/Element} el The element to listen on
15589  * @param {Object} config
15590  **/
15591 Roo.util.ClickRepeater = function(el, config)
15592 {
15593     this.el = Roo.get(el);
15594     this.el.unselectable();
15595
15596     Roo.apply(this, config);
15597
15598     this.addEvents({
15599     /**
15600      * @event mousedown
15601      * Fires when the mouse button is depressed.
15602      * @param {Roo.util.ClickRepeater} this
15603      */
15604         "mousedown" : true,
15605     /**
15606      * @event click
15607      * Fires on a specified interval during the time the element is pressed.
15608      * @param {Roo.util.ClickRepeater} this
15609      */
15610         "click" : true,
15611     /**
15612      * @event mouseup
15613      * Fires when the mouse key is released.
15614      * @param {Roo.util.ClickRepeater} this
15615      */
15616         "mouseup" : true
15617     });
15618
15619     this.el.on("mousedown", this.handleMouseDown, this);
15620     if(this.preventDefault || this.stopDefault){
15621         this.el.on("click", function(e){
15622             if(this.preventDefault){
15623                 e.preventDefault();
15624             }
15625             if(this.stopDefault){
15626                 e.stopEvent();
15627             }
15628         }, this);
15629     }
15630
15631     // allow inline handler
15632     if(this.handler){
15633         this.on("click", this.handler,  this.scope || this);
15634     }
15635
15636     Roo.util.ClickRepeater.superclass.constructor.call(this);
15637 };
15638
15639 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
15640     interval : 20,
15641     delay: 250,
15642     preventDefault : true,
15643     stopDefault : false,
15644     timer : 0,
15645
15646     // private
15647     handleMouseDown : function(){
15648         clearTimeout(this.timer);
15649         this.el.blur();
15650         if(this.pressClass){
15651             this.el.addClass(this.pressClass);
15652         }
15653         this.mousedownTime = new Date();
15654
15655         Roo.get(document).on("mouseup", this.handleMouseUp, this);
15656         this.el.on("mouseout", this.handleMouseOut, this);
15657
15658         this.fireEvent("mousedown", this);
15659         this.fireEvent("click", this);
15660         
15661         this.timer = this.click.defer(this.delay || this.interval, this);
15662     },
15663
15664     // private
15665     click : function(){
15666         this.fireEvent("click", this);
15667         this.timer = this.click.defer(this.getInterval(), this);
15668     },
15669
15670     // private
15671     getInterval: function(){
15672         if(!this.accelerate){
15673             return this.interval;
15674         }
15675         var pressTime = this.mousedownTime.getElapsed();
15676         if(pressTime < 500){
15677             return 400;
15678         }else if(pressTime < 1700){
15679             return 320;
15680         }else if(pressTime < 2600){
15681             return 250;
15682         }else if(pressTime < 3500){
15683             return 180;
15684         }else if(pressTime < 4400){
15685             return 140;
15686         }else if(pressTime < 5300){
15687             return 80;
15688         }else if(pressTime < 6200){
15689             return 50;
15690         }else{
15691             return 10;
15692         }
15693     },
15694
15695     // private
15696     handleMouseOut : function(){
15697         clearTimeout(this.timer);
15698         if(this.pressClass){
15699             this.el.removeClass(this.pressClass);
15700         }
15701         this.el.on("mouseover", this.handleMouseReturn, this);
15702     },
15703
15704     // private
15705     handleMouseReturn : function(){
15706         this.el.un("mouseover", this.handleMouseReturn);
15707         if(this.pressClass){
15708             this.el.addClass(this.pressClass);
15709         }
15710         this.click();
15711     },
15712
15713     // private
15714     handleMouseUp : function(){
15715         clearTimeout(this.timer);
15716         this.el.un("mouseover", this.handleMouseReturn);
15717         this.el.un("mouseout", this.handleMouseOut);
15718         Roo.get(document).un("mouseup", this.handleMouseUp);
15719         this.el.removeClass(this.pressClass);
15720         this.fireEvent("mouseup", this);
15721     }
15722 });/**
15723  * @class Roo.util.Clipboard
15724  * @static
15725  * 
15726  * Clipboard UTILS
15727  * 
15728  **/
15729 Roo.util.Clipboard = {
15730     /**
15731      * Writes a string to the clipboard - using the Clipboard API if https, otherwise using text area.
15732      * @param {String} text to copy to clipboard
15733      */
15734     write : function(text) {
15735         // navigator clipboard api needs a secure context (https)
15736         if (navigator.clipboard && window.isSecureContext) {
15737             // navigator clipboard api method'
15738             navigator.clipboard.writeText(text);
15739             return ;
15740         } 
15741         // text area method
15742         var ta = document.createElement("textarea");
15743         ta.value = text;
15744         // make the textarea out of viewport
15745         ta.style.position = "fixed";
15746         ta.style.left = "-999999px";
15747         ta.style.top = "-999999px";
15748         document.body.appendChild(ta);
15749         ta.focus();
15750         ta.select();
15751         document.execCommand('copy');
15752         (function() {
15753             ta.remove();
15754         }).defer(100);
15755         
15756     }
15757         
15758 }
15759     /*
15760  * Based on:
15761  * Ext JS Library 1.1.1
15762  * Copyright(c) 2006-2007, Ext JS, LLC.
15763  *
15764  * Originally Released Under LGPL - original licence link has changed is not relivant.
15765  *
15766  * Fork - LGPL
15767  * <script type="text/javascript">
15768  */
15769
15770  
15771 /**
15772  * @class Roo.KeyNav
15773  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
15774  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
15775  * way to implement custom navigation schemes for any UI component.</p>
15776  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
15777  * pageUp, pageDown, del, home, end.  Usage:</p>
15778  <pre><code>
15779 var nav = new Roo.KeyNav("my-element", {
15780     "left" : function(e){
15781         this.moveLeft(e.ctrlKey);
15782     },
15783     "right" : function(e){
15784         this.moveRight(e.ctrlKey);
15785     },
15786     "enter" : function(e){
15787         this.save();
15788     },
15789     scope : this
15790 });
15791 </code></pre>
15792  * @constructor
15793  * @param {String/HTMLElement/Roo.Element} el The element to bind to
15794  * @param {Object} config The config
15795  */
15796 Roo.KeyNav = function(el, config){
15797     this.el = Roo.get(el);
15798     Roo.apply(this, config);
15799     if(!this.disabled){
15800         this.disabled = true;
15801         this.enable();
15802     }
15803 };
15804
15805 Roo.KeyNav.prototype = {
15806     /**
15807      * @cfg {Boolean} disabled
15808      * True to disable this KeyNav instance (defaults to false)
15809      */
15810     disabled : false,
15811     /**
15812      * @cfg {String} defaultEventAction
15813      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
15814      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
15815      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
15816      */
15817     defaultEventAction: "stopEvent",
15818     /**
15819      * @cfg {Boolean} forceKeyDown
15820      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
15821      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
15822      * handle keydown instead of keypress.
15823      */
15824     forceKeyDown : false,
15825
15826     // private
15827     prepareEvent : function(e){
15828         var k = e.getKey();
15829         var h = this.keyToHandler[k];
15830         //if(h && this[h]){
15831         //    e.stopPropagation();
15832         //}
15833         if(Roo.isSafari && h && k >= 37 && k <= 40){
15834             e.stopEvent();
15835         }
15836     },
15837
15838     // private
15839     relay : function(e){
15840         var k = e.getKey();
15841         var h = this.keyToHandler[k];
15842         if(h && this[h]){
15843             if(this.doRelay(e, this[h], h) !== true){
15844                 e[this.defaultEventAction]();
15845             }
15846         }
15847     },
15848
15849     // private
15850     doRelay : function(e, h, hname){
15851         return h.call(this.scope || this, e);
15852     },
15853
15854     // possible handlers
15855     enter : false,
15856     left : false,
15857     right : false,
15858     up : false,
15859     down : false,
15860     tab : false,
15861     esc : false,
15862     pageUp : false,
15863     pageDown : false,
15864     del : false,
15865     home : false,
15866     end : false,
15867
15868     // quick lookup hash
15869     keyToHandler : {
15870         37 : "left",
15871         39 : "right",
15872         38 : "up",
15873         40 : "down",
15874         33 : "pageUp",
15875         34 : "pageDown",
15876         46 : "del",
15877         36 : "home",
15878         35 : "end",
15879         13 : "enter",
15880         27 : "esc",
15881         9  : "tab"
15882     },
15883
15884         /**
15885          * Enable this KeyNav
15886          */
15887         enable: function(){
15888                 if(this.disabled){
15889             // ie won't do special keys on keypress, no one else will repeat keys with keydown
15890             // the EventObject will normalize Safari automatically
15891             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
15892                 this.el.on("keydown", this.relay,  this);
15893             }else{
15894                 this.el.on("keydown", this.prepareEvent,  this);
15895                 this.el.on("keypress", this.relay,  this);
15896             }
15897                     this.disabled = false;
15898                 }
15899         },
15900
15901         /**
15902          * Disable this KeyNav
15903          */
15904         disable: function(){
15905                 if(!this.disabled){
15906                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
15907                 this.el.un("keydown", this.relay);
15908             }else{
15909                 this.el.un("keydown", this.prepareEvent);
15910                 this.el.un("keypress", this.relay);
15911             }
15912                     this.disabled = true;
15913                 }
15914         }
15915 };/*
15916  * Based on:
15917  * Ext JS Library 1.1.1
15918  * Copyright(c) 2006-2007, Ext JS, LLC.
15919  *
15920  * Originally Released Under LGPL - original licence link has changed is not relivant.
15921  *
15922  * Fork - LGPL
15923  * <script type="text/javascript">
15924  */
15925
15926  
15927 /**
15928  * @class Roo.KeyMap
15929  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
15930  * The constructor accepts the same config object as defined by {@link #addBinding}.
15931  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
15932  * combination it will call the function with this signature (if the match is a multi-key
15933  * combination the callback will still be called only once): (String key, Roo.EventObject e)
15934  * A KeyMap can also handle a string representation of keys.<br />
15935  * Usage:
15936  <pre><code>
15937 // map one key by key code
15938 var map = new Roo.KeyMap("my-element", {
15939     key: 13, // or Roo.EventObject.ENTER
15940     fn: myHandler,
15941     scope: myObject
15942 });
15943
15944 // map multiple keys to one action by string
15945 var map = new Roo.KeyMap("my-element", {
15946     key: "a\r\n\t",
15947     fn: myHandler,
15948     scope: myObject
15949 });
15950
15951 // map multiple keys to multiple actions by strings and array of codes
15952 var map = new Roo.KeyMap("my-element", [
15953     {
15954         key: [10,13],
15955         fn: function(){ alert("Return was pressed"); }
15956     }, {
15957         key: "abc",
15958         fn: function(){ alert('a, b or c was pressed'); }
15959     }, {
15960         key: "\t",
15961         ctrl:true,
15962         shift:true,
15963         fn: function(){ alert('Control + shift + tab was pressed.'); }
15964     }
15965 ]);
15966 </code></pre>
15967  * <b>Note: A KeyMap starts enabled</b>
15968  * @constructor
15969  * @param {String/HTMLElement/Roo.Element} el The element to bind to
15970  * @param {Object} config The config (see {@link #addBinding})
15971  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
15972  */
15973 Roo.KeyMap = function(el, config, eventName){
15974     this.el  = Roo.get(el);
15975     this.eventName = eventName || "keydown";
15976     this.bindings = [];
15977     if(config){
15978         this.addBinding(config);
15979     }
15980     this.enable();
15981 };
15982
15983 Roo.KeyMap.prototype = {
15984     /**
15985      * True to stop the event from bubbling and prevent the default browser action if the
15986      * key was handled by the KeyMap (defaults to false)
15987      * @type Boolean
15988      */
15989     stopEvent : false,
15990
15991     /**
15992      * Add a new binding to this KeyMap. The following config object properties are supported:
15993      * <pre>
15994 Property    Type             Description
15995 ----------  ---------------  ----------------------------------------------------------------------
15996 key         String/Array     A single keycode or an array of keycodes to handle
15997 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
15998 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
15999 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
16000 fn          Function         The function to call when KeyMap finds the expected key combination
16001 scope       Object           The scope of the callback function
16002 </pre>
16003      *
16004      * Usage:
16005      * <pre><code>
16006 // Create a KeyMap
16007 var map = new Roo.KeyMap(document, {
16008     key: Roo.EventObject.ENTER,
16009     fn: handleKey,
16010     scope: this
16011 });
16012
16013 //Add a new binding to the existing KeyMap later
16014 map.addBinding({
16015     key: 'abc',
16016     shift: true,
16017     fn: handleKey,
16018     scope: this
16019 });
16020 </code></pre>
16021      * @param {Object/Array} config A single KeyMap config or an array of configs
16022      */
16023         addBinding : function(config){
16024         if(config instanceof Array){
16025             for(var i = 0, len = config.length; i < len; i++){
16026                 this.addBinding(config[i]);
16027             }
16028             return;
16029         }
16030         var keyCode = config.key,
16031             shift = config.shift, 
16032             ctrl = config.ctrl, 
16033             alt = config.alt,
16034             fn = config.fn,
16035             scope = config.scope;
16036         if(typeof keyCode == "string"){
16037             var ks = [];
16038             var keyString = keyCode.toUpperCase();
16039             for(var j = 0, len = keyString.length; j < len; j++){
16040                 ks.push(keyString.charCodeAt(j));
16041             }
16042             keyCode = ks;
16043         }
16044         var keyArray = keyCode instanceof Array;
16045         var handler = function(e){
16046             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
16047                 var k = e.getKey();
16048                 if(keyArray){
16049                     for(var i = 0, len = keyCode.length; i < len; i++){
16050                         if(keyCode[i] == k){
16051                           if(this.stopEvent){
16052                               e.stopEvent();
16053                           }
16054                           fn.call(scope || window, k, e);
16055                           return;
16056                         }
16057                     }
16058                 }else{
16059                     if(k == keyCode){
16060                         if(this.stopEvent){
16061                            e.stopEvent();
16062                         }
16063                         fn.call(scope || window, k, e);
16064                     }
16065                 }
16066             }
16067         };
16068         this.bindings.push(handler);  
16069         },
16070
16071     /**
16072      * Shorthand for adding a single key listener
16073      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
16074      * following options:
16075      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
16076      * @param {Function} fn The function to call
16077      * @param {Object} scope (optional) The scope of the function
16078      */
16079     on : function(key, fn, scope){
16080         var keyCode, shift, ctrl, alt;
16081         if(typeof key == "object" && !(key instanceof Array)){
16082             keyCode = key.key;
16083             shift = key.shift;
16084             ctrl = key.ctrl;
16085             alt = key.alt;
16086         }else{
16087             keyCode = key;
16088         }
16089         this.addBinding({
16090             key: keyCode,
16091             shift: shift,
16092             ctrl: ctrl,
16093             alt: alt,
16094             fn: fn,
16095             scope: scope
16096         })
16097     },
16098
16099     // private
16100     handleKeyDown : function(e){
16101             if(this.enabled){ //just in case
16102             var b = this.bindings;
16103             for(var i = 0, len = b.length; i < len; i++){
16104                 b[i].call(this, e);
16105             }
16106             }
16107         },
16108         
16109         /**
16110          * Returns true if this KeyMap is enabled
16111          * @return {Boolean} 
16112          */
16113         isEnabled : function(){
16114             return this.enabled;  
16115         },
16116         
16117         /**
16118          * Enables this KeyMap
16119          */
16120         enable: function(){
16121                 if(!this.enabled){
16122                     this.el.on(this.eventName, this.handleKeyDown, this);
16123                     this.enabled = true;
16124                 }
16125         },
16126
16127         /**
16128          * Disable this KeyMap
16129          */
16130         disable: function(){
16131                 if(this.enabled){
16132                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
16133                     this.enabled = false;
16134                 }
16135         }
16136 };/*
16137  * Based on:
16138  * Ext JS Library 1.1.1
16139  * Copyright(c) 2006-2007, Ext JS, LLC.
16140  *
16141  * Originally Released Under LGPL - original licence link has changed is not relivant.
16142  *
16143  * Fork - LGPL
16144  * <script type="text/javascript">
16145  */
16146
16147  
16148 /**
16149  * @class Roo.util.TextMetrics
16150  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
16151  * wide, in pixels, a given block of text will be.
16152  * @static
16153  */
16154 Roo.util.TextMetrics = function(){
16155     var shared;
16156     return {
16157         /**
16158          * Measures the size of the specified text
16159          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
16160          * that can affect the size of the rendered text
16161          * @param {String} text The text to measure
16162          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
16163          * in order to accurately measure the text height
16164          * @return {Object} An object containing the text's size {width: (width), height: (height)}
16165          */
16166         measure : function(el, text, fixedWidth){
16167             if(!shared){
16168                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
16169             }
16170             shared.bind(el);
16171             shared.setFixedWidth(fixedWidth || 'auto');
16172             return shared.getSize(text);
16173         },
16174
16175         /**
16176          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
16177          * the overhead of multiple calls to initialize the style properties on each measurement.
16178          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
16179          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
16180          * in order to accurately measure the text height
16181          * @return {Roo.util.TextMetrics.Instance} instance The new instance
16182          */
16183         createInstance : function(el, fixedWidth){
16184             return Roo.util.TextMetrics.Instance(el, fixedWidth);
16185         }
16186     };
16187 }();
16188
16189 /**
16190  * @class Roo.util.TextMetrics.Instance
16191  * Instance of  TextMetrics Calcuation
16192  * @constructor
16193  * Create a new TextMetrics Instance
16194  * @param {Object} bindto
16195  * @param {Boolean} fixedWidth
16196  */
16197
16198 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth)
16199 {
16200     var ml = new Roo.Element(document.createElement('div'));
16201     document.body.appendChild(ml.dom);
16202     ml.position('absolute');
16203     ml.setLeftTop(-1000, -1000);
16204     ml.hide();
16205
16206     if(fixedWidth){
16207         ml.setWidth(fixedWidth);
16208     }
16209      
16210     var instance = {
16211         /**
16212          * Returns the size of the specified text based on the internal element's style and width properties
16213          * @param {String} text The text to measure
16214          * @return {Object} An object containing the text's size {width: (width), height: (height)}
16215          */
16216         getSize : function(text){
16217             ml.update(text);
16218             var s = ml.getSize();
16219             ml.update('');
16220             return s;
16221         },
16222
16223         /**
16224          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
16225          * that can affect the size of the rendered text
16226          * @param {String/HTMLElement} el The element, dom node or id
16227          */
16228         bind : function(el){
16229             ml.setStyle(
16230                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
16231             );
16232         },
16233
16234         /**
16235          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
16236          * to set a fixed width in order to accurately measure the text height.
16237          * @param {Number} width The width to set on the element
16238          */
16239         setFixedWidth : function(width){
16240             ml.setWidth(width);
16241         },
16242
16243         /**
16244          * Returns the measured width of the specified text
16245          * @param {String} text The text to measure
16246          * @return {Number} width The width in pixels
16247          */
16248         getWidth : function(text){
16249             ml.dom.style.width = 'auto';
16250             return this.getSize(text).width;
16251         },
16252
16253         /**
16254          * Returns the measured height of the specified text.  For multiline text, be sure to call
16255          * {@link #setFixedWidth} if necessary.
16256          * @param {String} text The text to measure
16257          * @return {Number} height The height in pixels
16258          */
16259         getHeight : function(text){
16260             return this.getSize(text).height;
16261         }
16262     };
16263
16264     instance.bind(bindTo);
16265
16266     return instance;
16267 };
16268
16269 // backwards compat
16270 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
16271  * Based on:
16272  * Ext JS Library 1.1.1
16273  * Copyright(c) 2006-2007, Ext JS, LLC.
16274  *
16275  * Originally Released Under LGPL - original licence link has changed is not relivant.
16276  *
16277  * Fork - LGPL
16278  * <script type="text/javascript">
16279  */
16280
16281 /**
16282  * @class Roo.state.Provider
16283  * Abstract base class for state provider implementations. This class provides methods
16284  * for encoding and decoding <b>typed</b> variables including dates and defines the 
16285  * Provider interface.
16286  */
16287 Roo.state.Provider = function(){
16288     /**
16289      * @event statechange
16290      * Fires when a state change occurs.
16291      * @param {Provider} this This state provider
16292      * @param {String} key The state key which was changed
16293      * @param {String} value The encoded value for the state
16294      */
16295     this.addEvents({
16296         "statechange": true
16297     });
16298     this.state = {};
16299     Roo.state.Provider.superclass.constructor.call(this);
16300 };
16301 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
16302     /**
16303      * Returns the current value for a key
16304      * @param {String} name The key name
16305      * @param {Mixed} defaultValue A default value to return if the key's value is not found
16306      * @return {Mixed} The state data
16307      */
16308     get : function(name, defaultValue){
16309         return typeof this.state[name] == "undefined" ?
16310             defaultValue : this.state[name];
16311     },
16312     
16313     /**
16314      * Clears a value from the state
16315      * @param {String} name The key name
16316      */
16317     clear : function(name){
16318         delete this.state[name];
16319         this.fireEvent("statechange", this, name, null);
16320     },
16321     
16322     /**
16323      * Sets the value for a key
16324      * @param {String} name The key name
16325      * @param {Mixed} value The value to set
16326      */
16327     set : function(name, value){
16328         this.state[name] = value;
16329         this.fireEvent("statechange", this, name, value);
16330     },
16331     
16332     /**
16333      * Decodes a string previously encoded with {@link #encodeValue}.
16334      * @param {String} value The value to decode
16335      * @return {Mixed} The decoded value
16336      */
16337     decodeValue : function(cookie){
16338         var re = /^(a|n|d|b|s|o)\:(.*)$/;
16339         var matches = re.exec(unescape(cookie));
16340         if(!matches || !matches[1]) {
16341             return; // non state cookie
16342         }
16343         var type = matches[1];
16344         var v = matches[2];
16345         switch(type){
16346             case "n":
16347                 return parseFloat(v);
16348             case "d":
16349                 return new Date(Date.parse(v));
16350             case "b":
16351                 return (v == "1");
16352             case "a":
16353                 var all = [];
16354                 var values = v.split("^");
16355                 for(var i = 0, len = values.length; i < len; i++){
16356                     all.push(this.decodeValue(values[i]));
16357                 }
16358                 return all;
16359            case "o":
16360                 var all = {};
16361                 var values = v.split("^");
16362                 for(var i = 0, len = values.length; i < len; i++){
16363                     var kv = values[i].split("=");
16364                     all[kv[0]] = this.decodeValue(kv[1]);
16365                 }
16366                 return all;
16367            default:
16368                 return v;
16369         }
16370     },
16371     
16372     /**
16373      * Encodes a value including type information.  Decode with {@link #decodeValue}.
16374      * @param {Mixed} value The value to encode
16375      * @return {String} The encoded value
16376      */
16377     encodeValue : function(v){
16378         var enc;
16379         if(typeof v == "number"){
16380             enc = "n:" + v;
16381         }else if(typeof v == "boolean"){
16382             enc = "b:" + (v ? "1" : "0");
16383         }else if(v instanceof Date){
16384             enc = "d:" + v.toGMTString();
16385         }else if(v instanceof Array){
16386             var flat = "";
16387             for(var i = 0, len = v.length; i < len; i++){
16388                 flat += this.encodeValue(v[i]);
16389                 if(i != len-1) {
16390                     flat += "^";
16391                 }
16392             }
16393             enc = "a:" + flat;
16394         }else if(typeof v == "object"){
16395             var flat = "";
16396             for(var key in v){
16397                 if(typeof v[key] != "function"){
16398                     flat += key + "=" + this.encodeValue(v[key]) + "^";
16399                 }
16400             }
16401             enc = "o:" + flat.substring(0, flat.length-1);
16402         }else{
16403             enc = "s:" + v;
16404         }
16405         return escape(enc);        
16406     }
16407 });
16408
16409 /*
16410  * Based on:
16411  * Ext JS Library 1.1.1
16412  * Copyright(c) 2006-2007, Ext JS, LLC.
16413  *
16414  * Originally Released Under LGPL - original licence link has changed is not relivant.
16415  *
16416  * Fork - LGPL
16417  * <script type="text/javascript">
16418  */
16419 /**
16420  * @class Roo.state.Manager
16421  * This is the global state manager. By default all components that are "state aware" check this class
16422  * for state information if you don't pass them a custom state provider. In order for this class
16423  * to be useful, it must be initialized with a provider when your application initializes.
16424  <pre><code>
16425 // in your initialization function
16426 init : function(){
16427    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
16428    ...
16429    // supposed you have a {@link Roo.BorderLayout}
16430    var layout = new Roo.BorderLayout(...);
16431    layout.restoreState();
16432    // or a {Roo.BasicDialog}
16433    var dialog = new Roo.BasicDialog(...);
16434    dialog.restoreState();
16435  </code></pre>
16436  * @static
16437  */
16438 Roo.state.Manager = function(){
16439     var provider = new Roo.state.Provider();
16440     
16441     return {
16442         /**
16443          * Configures the default state provider for your application
16444          * @param {Provider} stateProvider The state provider to set
16445          */
16446         setProvider : function(stateProvider){
16447             provider = stateProvider;
16448         },
16449         
16450         /**
16451          * Returns the current value for a key
16452          * @param {String} name The key name
16453          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
16454          * @return {Mixed} The state data
16455          */
16456         get : function(key, defaultValue){
16457             return provider.get(key, defaultValue);
16458         },
16459         
16460         /**
16461          * Sets the value for a key
16462          * @param {String} name The key name
16463          * @param {Mixed} value The state data
16464          */
16465          set : function(key, value){
16466             provider.set(key, value);
16467         },
16468         
16469         /**
16470          * Clears a value from the state
16471          * @param {String} name The key name
16472          */
16473         clear : function(key){
16474             provider.clear(key);
16475         },
16476         
16477         /**
16478          * Gets the currently configured state provider
16479          * @return {Provider} The state provider
16480          */
16481         getProvider : function(){
16482             return provider;
16483         }
16484     };
16485 }();
16486 /*
16487  * Based on:
16488  * Ext JS Library 1.1.1
16489  * Copyright(c) 2006-2007, Ext JS, LLC.
16490  *
16491  * Originally Released Under LGPL - original licence link has changed is not relivant.
16492  *
16493  * Fork - LGPL
16494  * <script type="text/javascript">
16495  */
16496 /**
16497  * @class Roo.state.CookieProvider
16498  * @extends Roo.state.Provider
16499  * The default Provider implementation which saves state via cookies.
16500  * <br />Usage:
16501  <pre><code>
16502    var cp = new Roo.state.CookieProvider({
16503        path: "/cgi-bin/",
16504        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
16505        domain: "roojs.com"
16506    })
16507    Roo.state.Manager.setProvider(cp);
16508  </code></pre>
16509  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
16510  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
16511  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
16512  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
16513  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
16514  * domain the page is running on including the 'www' like 'www.roojs.com')
16515  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
16516  * @constructor
16517  * Create a new CookieProvider
16518  * @param {Object} config The configuration object
16519  */
16520 Roo.state.CookieProvider = function(config){
16521     Roo.state.CookieProvider.superclass.constructor.call(this);
16522     this.path = "/";
16523     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
16524     this.domain = null;
16525     this.secure = false;
16526     Roo.apply(this, config);
16527     this.state = this.readCookies();
16528 };
16529
16530 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
16531     // private
16532     set : function(name, value){
16533         if(typeof value == "undefined" || value === null){
16534             this.clear(name);
16535             return;
16536         }
16537         this.setCookie(name, value);
16538         Roo.state.CookieProvider.superclass.set.call(this, name, value);
16539     },
16540
16541     // private
16542     clear : function(name){
16543         this.clearCookie(name);
16544         Roo.state.CookieProvider.superclass.clear.call(this, name);
16545     },
16546
16547     // private
16548     readCookies : function(){
16549         var cookies = {};
16550         var c = document.cookie + ";";
16551         var re = /\s?(.*?)=(.*?);/g;
16552         var matches;
16553         while((matches = re.exec(c)) != null){
16554             var name = matches[1];
16555             var value = matches[2];
16556             if(name && name.substring(0,3) == "ys-"){
16557                 cookies[name.substr(3)] = this.decodeValue(value);
16558             }
16559         }
16560         return cookies;
16561     },
16562
16563     // private
16564     setCookie : function(name, value){
16565         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
16566            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
16567            ((this.path == null) ? "" : ("; path=" + this.path)) +
16568            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
16569            ((this.secure == true) ? "; secure" : "");
16570     },
16571
16572     // private
16573     clearCookie : function(name){
16574         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
16575            ((this.path == null) ? "" : ("; path=" + this.path)) +
16576            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
16577            ((this.secure == true) ? "; secure" : "");
16578     }
16579 });/*
16580  * Based on:
16581  * Ext JS Library 1.1.1
16582  * Copyright(c) 2006-2007, Ext JS, LLC.
16583  *
16584  * Originally Released Under LGPL - original licence link has changed is not relivant.
16585  *
16586  * Fork - LGPL
16587  * <script type="text/javascript">
16588  */
16589  
16590
16591 /**
16592  * @class Roo.ComponentMgr
16593  * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
16594  * @static
16595  */
16596 Roo.ComponentMgr = function(){
16597     var all = new Roo.util.MixedCollection();
16598
16599     return {
16600         /**
16601          * Registers a component.
16602          * @param {Roo.Component} c The component
16603          */
16604         register : function(c){
16605             all.add(c);
16606         },
16607
16608         /**
16609          * Unregisters a component.
16610          * @param {Roo.Component} c The component
16611          */
16612         unregister : function(c){
16613             all.remove(c);
16614         },
16615
16616         /**
16617          * Returns a component by id
16618          * @param {String} id The component id
16619          */
16620         get : function(id){
16621             return all.get(id);
16622         },
16623
16624         /**
16625          * Registers a function that will be called when a specified component is added to ComponentMgr
16626          * @param {String} id The component id
16627          * @param {Funtction} fn The callback function
16628          * @param {Object} scope The scope of the callback
16629          */
16630         onAvailable : function(id, fn, scope){
16631             all.on("add", function(index, o){
16632                 if(o.id == id){
16633                     fn.call(scope || o, o);
16634                     all.un("add", fn, scope);
16635                 }
16636             });
16637         }
16638     };
16639 }();/*
16640  * Based on:
16641  * Ext JS Library 1.1.1
16642  * Copyright(c) 2006-2007, Ext JS, LLC.
16643  *
16644  * Originally Released Under LGPL - original licence link has changed is not relivant.
16645  *
16646  * Fork - LGPL
16647  * <script type="text/javascript">
16648  */
16649  
16650 /**
16651  * @class Roo.Component
16652  * @extends Roo.util.Observable
16653  * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
16654  * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
16655  * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
16656  * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
16657  * All visual components (widgets) that require rendering into a layout should subclass Component.
16658  * @constructor
16659  * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
16660  * 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
16661  * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
16662  */
16663 Roo.Component = function(config){
16664     config = config || {};
16665     if(config.tagName || config.dom || typeof config == "string"){ // element object
16666         config = {el: config, id: config.id || config};
16667     }
16668     this.initialConfig = config;
16669
16670     Roo.apply(this, config);
16671     this.addEvents({
16672         /**
16673          * @event disable
16674          * Fires after the component is disabled.
16675              * @param {Roo.Component} this
16676              */
16677         disable : true,
16678         /**
16679          * @event enable
16680          * Fires after the component is enabled.
16681              * @param {Roo.Component} this
16682              */
16683         enable : true,
16684         /**
16685          * @event beforeshow
16686          * Fires before the component is shown.  Return false to stop the show.
16687              * @param {Roo.Component} this
16688              */
16689         beforeshow : true,
16690         /**
16691          * @event show
16692          * Fires after the component is shown.
16693              * @param {Roo.Component} this
16694              */
16695         show : true,
16696         /**
16697          * @event beforehide
16698          * Fires before the component is hidden. Return false to stop the hide.
16699              * @param {Roo.Component} this
16700              */
16701         beforehide : true,
16702         /**
16703          * @event hide
16704          * Fires after the component is hidden.
16705              * @param {Roo.Component} this
16706              */
16707         hide : true,
16708         /**
16709          * @event beforerender
16710          * Fires before the component is rendered. Return false to stop the render.
16711              * @param {Roo.Component} this
16712              */
16713         beforerender : true,
16714         /**
16715          * @event render
16716          * Fires after the component is rendered.
16717              * @param {Roo.Component} this
16718              */
16719         render : true,
16720         /**
16721          * @event beforedestroy
16722          * Fires before the component is destroyed. Return false to stop the destroy.
16723              * @param {Roo.Component} this
16724              */
16725         beforedestroy : true,
16726         /**
16727          * @event destroy
16728          * Fires after the component is destroyed.
16729              * @param {Roo.Component} this
16730              */
16731         destroy : true
16732     });
16733     if(!this.id){
16734         this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
16735     }
16736     Roo.ComponentMgr.register(this);
16737     Roo.Component.superclass.constructor.call(this);
16738     this.initComponent();
16739     if(this.renderTo){ // not supported by all components yet. use at your own risk!
16740         this.render(this.renderTo);
16741         delete this.renderTo;
16742     }
16743 };
16744
16745 /** @private */
16746 Roo.Component.AUTO_ID = 1000;
16747
16748 Roo.extend(Roo.Component, Roo.util.Observable, {
16749     /**
16750      * @scope Roo.Component.prototype
16751      * @type {Boolean}
16752      * true if this component is hidden. Read-only.
16753      */
16754     hidden : false,
16755     /**
16756      * @type {Boolean}
16757      * true if this component is disabled. Read-only.
16758      */
16759     disabled : false,
16760     /**
16761      * @type {Boolean}
16762      * true if this component has been rendered. Read-only.
16763      */
16764     rendered : false,
16765     
16766     /** @cfg {String} disableClass
16767      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
16768      */
16769     disabledClass : "x-item-disabled",
16770         /** @cfg {Boolean} allowDomMove
16771          * Whether the component can move the Dom node when rendering (defaults to true).
16772          */
16773     allowDomMove : true,
16774     /** @cfg {String} hideMode (display|visibility)
16775      * How this component should hidden. Supported values are
16776      * "visibility" (css visibility), "offsets" (negative offset position) and
16777      * "display" (css display) - defaults to "display".
16778      */
16779     hideMode: 'display',
16780
16781     /** @private */
16782     ctype : "Roo.Component",
16783
16784     /**
16785      * @cfg {String} actionMode 
16786      * which property holds the element that used for  hide() / show() / disable() / enable()
16787      * default is 'el' for forms you probably want to set this to fieldEl 
16788      */
16789     actionMode : "el",
16790
16791     /** @private */
16792     getActionEl : function(){
16793         return this[this.actionMode];
16794     },
16795
16796     initComponent : Roo.emptyFn,
16797     /**
16798      * If this is a lazy rendering component, render it to its container element.
16799      * @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.
16800      */
16801     render : function(container, position){
16802         
16803         if(this.rendered){
16804             return this;
16805         }
16806         
16807         if(this.fireEvent("beforerender", this) === false){
16808             return false;
16809         }
16810         
16811         if(!container && this.el){
16812             this.el = Roo.get(this.el);
16813             container = this.el.dom.parentNode;
16814             this.allowDomMove = false;
16815         }
16816         this.container = Roo.get(container);
16817         this.rendered = true;
16818         if(position !== undefined){
16819             if(typeof position == 'number'){
16820                 position = this.container.dom.childNodes[position];
16821             }else{
16822                 position = Roo.getDom(position);
16823             }
16824         }
16825         this.onRender(this.container, position || null);
16826         if(this.cls){
16827             this.el.addClass(this.cls);
16828             delete this.cls;
16829         }
16830         if(this.style){
16831             this.el.applyStyles(this.style);
16832             delete this.style;
16833         }
16834         this.fireEvent("render", this);
16835         this.afterRender(this.container);
16836         if(this.hidden){
16837             this.hide();
16838         }
16839         if(this.disabled){
16840             this.disable();
16841         }
16842
16843         return this;
16844         
16845     },
16846
16847     /** @private */
16848     // default function is not really useful
16849     onRender : function(ct, position){
16850         if(this.el){
16851             this.el = Roo.get(this.el);
16852             if(this.allowDomMove !== false){
16853                 ct.dom.insertBefore(this.el.dom, position);
16854             }
16855         }
16856     },
16857
16858     /** @private */
16859     getAutoCreate : function(){
16860         var cfg = typeof this.autoCreate == "object" ?
16861                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
16862         if(this.id && !cfg.id){
16863             cfg.id = this.id;
16864         }
16865         return cfg;
16866     },
16867
16868     /** @private */
16869     afterRender : Roo.emptyFn,
16870
16871     /**
16872      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
16873      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
16874      */
16875     destroy : function(){
16876         if(this.fireEvent("beforedestroy", this) !== false){
16877             this.purgeListeners();
16878             this.beforeDestroy();
16879             if(this.rendered){
16880                 this.el.removeAllListeners();
16881                 this.el.remove();
16882                 if(this.actionMode == "container"){
16883                     this.container.remove();
16884                 }
16885             }
16886             this.onDestroy();
16887             Roo.ComponentMgr.unregister(this);
16888             this.fireEvent("destroy", this);
16889         }
16890     },
16891
16892         /** @private */
16893     beforeDestroy : function(){
16894
16895     },
16896
16897         /** @private */
16898         onDestroy : function(){
16899
16900     },
16901
16902     /**
16903      * Returns the underlying {@link Roo.Element}.
16904      * @return {Roo.Element} The element
16905      */
16906     getEl : function(){
16907         return this.el;
16908     },
16909
16910     /**
16911      * Returns the id of this component.
16912      * @return {String}
16913      */
16914     getId : function(){
16915         return this.id;
16916     },
16917
16918     /**
16919      * Try to focus this component.
16920      * @param {Boolean} selectText True to also select the text in this component (if applicable)
16921      * @return {Roo.Component} this
16922      */
16923     focus : function(selectText){
16924         if(this.rendered){
16925             this.el.focus();
16926             if(selectText === true){
16927                 this.el.dom.select();
16928             }
16929         }
16930         return this;
16931     },
16932
16933     /** @private */
16934     blur : function(){
16935         if(this.rendered){
16936             this.el.blur();
16937         }
16938         return this;
16939     },
16940
16941     /**
16942      * Disable this component.
16943      * @return {Roo.Component} this
16944      */
16945     disable : function(){
16946         if(this.rendered){
16947             this.onDisable();
16948         }
16949         this.disabled = true;
16950         this.fireEvent("disable", this);
16951         return this;
16952     },
16953
16954         // private
16955     onDisable : function(){
16956         this.getActionEl().addClass(this.disabledClass);
16957         this.el.dom.disabled = true;
16958     },
16959
16960     /**
16961      * Enable this component.
16962      * @return {Roo.Component} this
16963      */
16964     enable : function(){
16965         if(this.rendered){
16966             this.onEnable();
16967         }
16968         this.disabled = false;
16969         this.fireEvent("enable", this);
16970         return this;
16971     },
16972
16973         // private
16974     onEnable : function(){
16975         this.getActionEl().removeClass(this.disabledClass);
16976         this.el.dom.disabled = false;
16977     },
16978
16979     /**
16980      * Convenience function for setting disabled/enabled by boolean.
16981      * @param {Boolean} disabled
16982      */
16983     setDisabled : function(disabled){
16984         this[disabled ? "disable" : "enable"]();
16985     },
16986
16987     /**
16988      * Show this component.
16989      * @return {Roo.Component} this
16990      */
16991     show: function(){
16992         if(this.fireEvent("beforeshow", this) !== false){
16993             this.hidden = false;
16994             if(this.rendered){
16995                 this.onShow();
16996             }
16997             this.fireEvent("show", this);
16998         }
16999         return this;
17000     },
17001
17002     // private
17003     onShow : function(){
17004         var ae = this.getActionEl();
17005         if(this.hideMode == 'visibility'){
17006             ae.dom.style.visibility = "visible";
17007         }else if(this.hideMode == 'offsets'){
17008             ae.removeClass('x-hidden');
17009         }else{
17010             ae.dom.style.display = "";
17011         }
17012     },
17013
17014     /**
17015      * Hide this component.
17016      * @return {Roo.Component} this
17017      */
17018     hide: function(){
17019         if(this.fireEvent("beforehide", this) !== false){
17020             this.hidden = true;
17021             if(this.rendered){
17022                 this.onHide();
17023             }
17024             this.fireEvent("hide", this);
17025         }
17026         return this;
17027     },
17028
17029     // private
17030     onHide : function(){
17031         var ae = this.getActionEl();
17032         if(this.hideMode == 'visibility'){
17033             ae.dom.style.visibility = "hidden";
17034         }else if(this.hideMode == 'offsets'){
17035             ae.addClass('x-hidden');
17036         }else{
17037             ae.dom.style.display = "none";
17038         }
17039     },
17040
17041     /**
17042      * Convenience function to hide or show this component by boolean.
17043      * @param {Boolean} visible True to show, false to hide
17044      * @return {Roo.Component} this
17045      */
17046     setVisible: function(visible){
17047         if(visible) {
17048             this.show();
17049         }else{
17050             this.hide();
17051         }
17052         return this;
17053     },
17054
17055     /**
17056      * Returns true if this component is visible.
17057      */
17058     isVisible : function(){
17059         return this.getActionEl().isVisible();
17060     },
17061
17062     cloneConfig : function(overrides){
17063         overrides = overrides || {};
17064         var id = overrides.id || Roo.id();
17065         var cfg = Roo.applyIf(overrides, this.initialConfig);
17066         cfg.id = id; // prevent dup id
17067         return new this.constructor(cfg);
17068     }
17069 });/*
17070  * Based on:
17071  * Ext JS Library 1.1.1
17072  * Copyright(c) 2006-2007, Ext JS, LLC.
17073  *
17074  * Originally Released Under LGPL - original licence link has changed is not relivant.
17075  *
17076  * Fork - LGPL
17077  * <script type="text/javascript">
17078  */
17079
17080 /**
17081  * @class Roo.BoxComponent
17082  * @extends Roo.Component
17083  * Base class for any visual {@link Roo.Component} that uses a box container.  BoxComponent provides automatic box
17084  * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model.  All
17085  * container classes should subclass BoxComponent so that they will work consistently when nested within other Roo
17086  * layout containers.
17087  * @constructor
17088  * @param {Roo.Element/String/Object} config The configuration options.
17089  */
17090 Roo.BoxComponent = function(config){
17091     Roo.Component.call(this, config);
17092     this.addEvents({
17093         /**
17094          * @event resize
17095          * Fires after the component is resized.
17096              * @param {Roo.Component} this
17097              * @param {Number} adjWidth The box-adjusted width that was set
17098              * @param {Number} adjHeight The box-adjusted height that was set
17099              * @param {Number} rawWidth The width that was originally specified
17100              * @param {Number} rawHeight The height that was originally specified
17101              */
17102         resize : true,
17103         /**
17104          * @event move
17105          * Fires after the component is moved.
17106              * @param {Roo.Component} this
17107              * @param {Number} x The new x position
17108              * @param {Number} y The new y position
17109              */
17110         move : true
17111     });
17112 };
17113
17114 Roo.extend(Roo.BoxComponent, Roo.Component, {
17115     // private, set in afterRender to signify that the component has been rendered
17116     boxReady : false,
17117     // private, used to defer height settings to subclasses
17118     deferHeight: false,
17119     /** @cfg {Number} width
17120      * width (optional) size of component
17121      */
17122      /** @cfg {Number} height
17123      * height (optional) size of component
17124      */
17125      
17126     /**
17127      * Sets the width and height of the component.  This method fires the resize event.  This method can accept
17128      * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
17129      * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
17130      * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
17131      * @return {Roo.BoxComponent} this
17132      */
17133     setSize : function(w, h){
17134         // support for standard size objects
17135         if(typeof w == 'object'){
17136             h = w.height;
17137             w = w.width;
17138         }
17139         // not rendered
17140         if(!this.boxReady){
17141             this.width = w;
17142             this.height = h;
17143             return this;
17144         }
17145
17146         // prevent recalcs when not needed
17147         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
17148             return this;
17149         }
17150         this.lastSize = {width: w, height: h};
17151
17152         var adj = this.adjustSize(w, h);
17153         var aw = adj.width, ah = adj.height;
17154         if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
17155             var rz = this.getResizeEl();
17156             if(!this.deferHeight && aw !== undefined && ah !== undefined){
17157                 rz.setSize(aw, ah);
17158             }else if(!this.deferHeight && ah !== undefined){
17159                 rz.setHeight(ah);
17160             }else if(aw !== undefined){
17161                 rz.setWidth(aw);
17162             }
17163             this.onResize(aw, ah, w, h);
17164             this.fireEvent('resize', this, aw, ah, w, h);
17165         }
17166         return this;
17167     },
17168
17169     /**
17170      * Gets the current size of the component's underlying element.
17171      * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
17172      */
17173     getSize : function(){
17174         return this.el.getSize();
17175     },
17176
17177     /**
17178      * Gets the current XY position of the component's underlying element.
17179      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
17180      * @return {Array} The XY position of the element (e.g., [100, 200])
17181      */
17182     getPosition : function(local){
17183         if(local === true){
17184             return [this.el.getLeft(true), this.el.getTop(true)];
17185         }
17186         return this.xy || this.el.getXY();
17187     },
17188
17189     /**
17190      * Gets the current box measurements of the component's underlying element.
17191      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
17192      * @returns {Object} box An object in the format {x, y, width, height}
17193      */
17194     getBox : function(local){
17195         var s = this.el.getSize();
17196         if(local){
17197             s.x = this.el.getLeft(true);
17198             s.y = this.el.getTop(true);
17199         }else{
17200             var xy = this.xy || this.el.getXY();
17201             s.x = xy[0];
17202             s.y = xy[1];
17203         }
17204         return s;
17205     },
17206
17207     /**
17208      * Sets the current box measurements of the component's underlying element.
17209      * @param {Object} box An object in the format {x, y, width, height}
17210      * @returns {Roo.BoxComponent} this
17211      */
17212     updateBox : function(box){
17213         this.setSize(box.width, box.height);
17214         this.setPagePosition(box.x, box.y);
17215         return this;
17216     },
17217
17218     // protected
17219     getResizeEl : function(){
17220         return this.resizeEl || this.el;
17221     },
17222
17223     // protected
17224     getPositionEl : function(){
17225         return this.positionEl || this.el;
17226     },
17227
17228     /**
17229      * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
17230      * This method fires the move event.
17231      * @param {Number} left The new left
17232      * @param {Number} top The new top
17233      * @returns {Roo.BoxComponent} this
17234      */
17235     setPosition : function(x, y){
17236         this.x = x;
17237         this.y = y;
17238         if(!this.boxReady){
17239             return this;
17240         }
17241         var adj = this.adjustPosition(x, y);
17242         var ax = adj.x, ay = adj.y;
17243
17244         var el = this.getPositionEl();
17245         if(ax !== undefined || ay !== undefined){
17246             if(ax !== undefined && ay !== undefined){
17247                 el.setLeftTop(ax, ay);
17248             }else if(ax !== undefined){
17249                 el.setLeft(ax);
17250             }else if(ay !== undefined){
17251                 el.setTop(ay);
17252             }
17253             this.onPosition(ax, ay);
17254             this.fireEvent('move', this, ax, ay);
17255         }
17256         return this;
17257     },
17258
17259     /**
17260      * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
17261      * This method fires the move event.
17262      * @param {Number} x The new x position
17263      * @param {Number} y The new y position
17264      * @returns {Roo.BoxComponent} this
17265      */
17266     setPagePosition : function(x, y){
17267         this.pageX = x;
17268         this.pageY = y;
17269         if(!this.boxReady){
17270             return;
17271         }
17272         if(x === undefined || y === undefined){ // cannot translate undefined points
17273             return;
17274         }
17275         var p = this.el.translatePoints(x, y);
17276         this.setPosition(p.left, p.top);
17277         return this;
17278     },
17279
17280     // private
17281     onRender : function(ct, position){
17282         Roo.BoxComponent.superclass.onRender.call(this, ct, position);
17283         if(this.resizeEl){
17284             this.resizeEl = Roo.get(this.resizeEl);
17285         }
17286         if(this.positionEl){
17287             this.positionEl = Roo.get(this.positionEl);
17288         }
17289     },
17290
17291     // private
17292     afterRender : function(){
17293         Roo.BoxComponent.superclass.afterRender.call(this);
17294         this.boxReady = true;
17295         this.setSize(this.width, this.height);
17296         if(this.x || this.y){
17297             this.setPosition(this.x, this.y);
17298         }
17299         if(this.pageX || this.pageY){
17300             this.setPagePosition(this.pageX, this.pageY);
17301         }
17302     },
17303
17304     /**
17305      * Force the component's size to recalculate based on the underlying element's current height and width.
17306      * @returns {Roo.BoxComponent} this
17307      */
17308     syncSize : function(){
17309         delete this.lastSize;
17310         this.setSize(this.el.getWidth(), this.el.getHeight());
17311         return this;
17312     },
17313
17314     /**
17315      * Called after the component is resized, this method is empty by default but can be implemented by any
17316      * subclass that needs to perform custom logic after a resize occurs.
17317      * @param {Number} adjWidth The box-adjusted width that was set
17318      * @param {Number} adjHeight The box-adjusted height that was set
17319      * @param {Number} rawWidth The width that was originally specified
17320      * @param {Number} rawHeight The height that was originally specified
17321      */
17322     onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
17323
17324     },
17325
17326     /**
17327      * Called after the component is moved, this method is empty by default but can be implemented by any
17328      * subclass that needs to perform custom logic after a move occurs.
17329      * @param {Number} x The new x position
17330      * @param {Number} y The new y position
17331      */
17332     onPosition : function(x, y){
17333
17334     },
17335
17336     // private
17337     adjustSize : function(w, h){
17338         if(this.autoWidth){
17339             w = 'auto';
17340         }
17341         if(this.autoHeight){
17342             h = 'auto';
17343         }
17344         return {width : w, height: h};
17345     },
17346
17347     // private
17348     adjustPosition : function(x, y){
17349         return {x : x, y: y};
17350     }
17351 });/*
17352  * Based on:
17353  * Ext JS Library 1.1.1
17354  * Copyright(c) 2006-2007, Ext JS, LLC.
17355  *
17356  * Originally Released Under LGPL - original licence link has changed is not relivant.
17357  *
17358  * Fork - LGPL
17359  * <script type="text/javascript">
17360  */
17361  (function(){ 
17362 /**
17363  * @class Roo.Layer
17364  * @extends Roo.Element
17365  * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
17366  * automatic maintaining of shadow/shim positions.
17367  * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
17368  * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
17369  * you can pass a string with a CSS class name. False turns off the shadow.
17370  * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
17371  * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
17372  * @cfg {String} cls CSS class to add to the element
17373  * @cfg {Number} zindex Starting z-index (defaults to 11000)
17374  * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
17375  * @constructor
17376  * @param {Object} config An object with config options.
17377  * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
17378  */
17379
17380 Roo.Layer = function(config, existingEl){
17381     config = config || {};
17382     var dh = Roo.DomHelper;
17383     var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
17384     if(existingEl){
17385         this.dom = Roo.getDom(existingEl);
17386     }
17387     if(!this.dom){
17388         var o = config.dh || {tag: "div", cls: "x-layer"};
17389         this.dom = dh.append(pel, o);
17390     }
17391     if(config.cls){
17392         this.addClass(config.cls);
17393     }
17394     this.constrain = config.constrain !== false;
17395     this.visibilityMode = Roo.Element.VISIBILITY;
17396     if(config.id){
17397         this.id = this.dom.id = config.id;
17398     }else{
17399         this.id = Roo.id(this.dom);
17400     }
17401     this.zindex = config.zindex || this.getZIndex();
17402     this.position("absolute", this.zindex);
17403     if(config.shadow){
17404         this.shadowOffset = config.shadowOffset || 4;
17405         this.shadow = new Roo.Shadow({
17406             offset : this.shadowOffset,
17407             mode : config.shadow
17408         });
17409     }else{
17410         this.shadowOffset = 0;
17411     }
17412     this.useShim = config.shim !== false && Roo.useShims;
17413     this.useDisplay = config.useDisplay;
17414     this.hide();
17415 };
17416
17417 var supr = Roo.Element.prototype;
17418
17419 // shims are shared among layer to keep from having 100 iframes
17420 var shims = [];
17421
17422 Roo.extend(Roo.Layer, Roo.Element, {
17423
17424     getZIndex : function(){
17425         return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
17426     },
17427
17428     getShim : function(){
17429         if(!this.useShim){
17430             return null;
17431         }
17432         if(this.shim){
17433             return this.shim;
17434         }
17435         var shim = shims.shift();
17436         if(!shim){
17437             shim = this.createShim();
17438             shim.enableDisplayMode('block');
17439             shim.dom.style.display = 'none';
17440             shim.dom.style.visibility = 'visible';
17441         }
17442         var pn = this.dom.parentNode;
17443         if(shim.dom.parentNode != pn){
17444             pn.insertBefore(shim.dom, this.dom);
17445         }
17446         shim.setStyle('z-index', this.getZIndex()-2);
17447         this.shim = shim;
17448         return shim;
17449     },
17450
17451     hideShim : function(){
17452         if(this.shim){
17453             this.shim.setDisplayed(false);
17454             shims.push(this.shim);
17455             delete this.shim;
17456         }
17457     },
17458
17459     disableShadow : function(){
17460         if(this.shadow){
17461             this.shadowDisabled = true;
17462             this.shadow.hide();
17463             this.lastShadowOffset = this.shadowOffset;
17464             this.shadowOffset = 0;
17465         }
17466     },
17467
17468     enableShadow : function(show){
17469         if(this.shadow){
17470             this.shadowDisabled = false;
17471             this.shadowOffset = this.lastShadowOffset;
17472             delete this.lastShadowOffset;
17473             if(show){
17474                 this.sync(true);
17475             }
17476         }
17477     },
17478
17479     // private
17480     // this code can execute repeatedly in milliseconds (i.e. during a drag) so
17481     // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
17482     sync : function(doShow){
17483         var sw = this.shadow;
17484         if(!this.updating && this.isVisible() && (sw || this.useShim)){
17485             var sh = this.getShim();
17486
17487             var w = this.getWidth(),
17488                 h = this.getHeight();
17489
17490             var l = this.getLeft(true),
17491                 t = this.getTop(true);
17492
17493             if(sw && !this.shadowDisabled){
17494                 if(doShow && !sw.isVisible()){
17495                     sw.show(this);
17496                 }else{
17497                     sw.realign(l, t, w, h);
17498                 }
17499                 if(sh){
17500                     if(doShow){
17501                        sh.show();
17502                     }
17503                     // fit the shim behind the shadow, so it is shimmed too
17504                     var a = sw.adjusts, s = sh.dom.style;
17505                     s.left = (Math.min(l, l+a.l))+"px";
17506                     s.top = (Math.min(t, t+a.t))+"px";
17507                     s.width = (w+a.w)+"px";
17508                     s.height = (h+a.h)+"px";
17509                 }
17510             }else if(sh){
17511                 if(doShow){
17512                    sh.show();
17513                 }
17514                 sh.setSize(w, h);
17515                 sh.setLeftTop(l, t);
17516             }
17517             
17518         }
17519     },
17520
17521     // private
17522     destroy : function(){
17523         this.hideShim();
17524         if(this.shadow){
17525             this.shadow.hide();
17526         }
17527         this.removeAllListeners();
17528         var pn = this.dom.parentNode;
17529         if(pn){
17530             pn.removeChild(this.dom);
17531         }
17532         Roo.Element.uncache(this.id);
17533     },
17534
17535     remove : function(){
17536         this.destroy();
17537     },
17538
17539     // private
17540     beginUpdate : function(){
17541         this.updating = true;
17542     },
17543
17544     // private
17545     endUpdate : function(){
17546         this.updating = false;
17547         this.sync(true);
17548     },
17549
17550     // private
17551     hideUnders : function(negOffset){
17552         if(this.shadow){
17553             this.shadow.hide();
17554         }
17555         this.hideShim();
17556     },
17557
17558     // private
17559     constrainXY : function(){
17560         if(this.constrain){
17561             var vw = Roo.lib.Dom.getViewWidth(),
17562                 vh = Roo.lib.Dom.getViewHeight();
17563             var s = Roo.get(document).getScroll();
17564
17565             var xy = this.getXY();
17566             var x = xy[0], y = xy[1];   
17567             var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
17568             // only move it if it needs it
17569             var moved = false;
17570             // first validate right/bottom
17571             if((x + w) > vw+s.left){
17572                 x = vw - w - this.shadowOffset;
17573                 moved = true;
17574             }
17575             if((y + h) > vh+s.top){
17576                 y = vh - h - this.shadowOffset;
17577                 moved = true;
17578             }
17579             // then make sure top/left isn't negative
17580             if(x < s.left){
17581                 x = s.left;
17582                 moved = true;
17583             }
17584             if(y < s.top){
17585                 y = s.top;
17586                 moved = true;
17587             }
17588             if(moved){
17589                 if(this.avoidY){
17590                     var ay = this.avoidY;
17591                     if(y <= ay && (y+h) >= ay){
17592                         y = ay-h-5;   
17593                     }
17594                 }
17595                 xy = [x, y];
17596                 this.storeXY(xy);
17597                 supr.setXY.call(this, xy);
17598                 this.sync();
17599             }
17600         }
17601     },
17602
17603     isVisible : function(){
17604         return this.visible;    
17605     },
17606
17607     // private
17608     showAction : function(){
17609         this.visible = true; // track visibility to prevent getStyle calls
17610         if(this.useDisplay === true){
17611             this.setDisplayed("");
17612         }else if(this.lastXY){
17613             supr.setXY.call(this, this.lastXY);
17614         }else if(this.lastLT){
17615             supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
17616         }
17617     },
17618
17619     // private
17620     hideAction : function(){
17621         this.visible = false;
17622         if(this.useDisplay === true){
17623             this.setDisplayed(false);
17624         }else{
17625             this.setLeftTop(-10000,-10000);
17626         }
17627     },
17628
17629     // overridden Element method
17630     setVisible : function(v, a, d, c, e){
17631         if(v){
17632             this.showAction();
17633         }
17634         if(a && v){
17635             var cb = function(){
17636                 this.sync(true);
17637                 if(c){
17638                     c();
17639                 }
17640             }.createDelegate(this);
17641             supr.setVisible.call(this, true, true, d, cb, e);
17642         }else{
17643             if(!v){
17644                 this.hideUnders(true);
17645             }
17646             var cb = c;
17647             if(a){
17648                 cb = function(){
17649                     this.hideAction();
17650                     if(c){
17651                         c();
17652                     }
17653                 }.createDelegate(this);
17654             }
17655             supr.setVisible.call(this, v, a, d, cb, e);
17656             if(v){
17657                 this.sync(true);
17658             }else if(!a){
17659                 this.hideAction();
17660             }
17661         }
17662     },
17663
17664     storeXY : function(xy){
17665         delete this.lastLT;
17666         this.lastXY = xy;
17667     },
17668
17669     storeLeftTop : function(left, top){
17670         delete this.lastXY;
17671         this.lastLT = [left, top];
17672     },
17673
17674     // private
17675     beforeFx : function(){
17676         this.beforeAction();
17677         return Roo.Layer.superclass.beforeFx.apply(this, arguments);
17678     },
17679
17680     // private
17681     afterFx : function(){
17682         Roo.Layer.superclass.afterFx.apply(this, arguments);
17683         this.sync(this.isVisible());
17684     },
17685
17686     // private
17687     beforeAction : function(){
17688         if(!this.updating && this.shadow){
17689             this.shadow.hide();
17690         }
17691     },
17692
17693     // overridden Element method
17694     setLeft : function(left){
17695         this.storeLeftTop(left, this.getTop(true));
17696         supr.setLeft.apply(this, arguments);
17697         this.sync();
17698     },
17699
17700     setTop : function(top){
17701         this.storeLeftTop(this.getLeft(true), top);
17702         supr.setTop.apply(this, arguments);
17703         this.sync();
17704     },
17705
17706     setLeftTop : function(left, top){
17707         this.storeLeftTop(left, top);
17708         supr.setLeftTop.apply(this, arguments);
17709         this.sync();
17710     },
17711
17712     setXY : function(xy, a, d, c, e){
17713         this.fixDisplay();
17714         this.beforeAction();
17715         this.storeXY(xy);
17716         var cb = this.createCB(c);
17717         supr.setXY.call(this, xy, a, d, cb, e);
17718         if(!a){
17719             cb();
17720         }
17721     },
17722
17723     // private
17724     createCB : function(c){
17725         var el = this;
17726         return function(){
17727             el.constrainXY();
17728             el.sync(true);
17729             if(c){
17730                 c();
17731             }
17732         };
17733     },
17734
17735     // overridden Element method
17736     setX : function(x, a, d, c, e){
17737         this.setXY([x, this.getY()], a, d, c, e);
17738     },
17739
17740     // overridden Element method
17741     setY : function(y, a, d, c, e){
17742         this.setXY([this.getX(), y], a, d, c, e);
17743     },
17744
17745     // overridden Element method
17746     setSize : function(w, h, a, d, c, e){
17747         this.beforeAction();
17748         var cb = this.createCB(c);
17749         supr.setSize.call(this, w, h, a, d, cb, e);
17750         if(!a){
17751             cb();
17752         }
17753     },
17754
17755     // overridden Element method
17756     setWidth : function(w, a, d, c, e){
17757         this.beforeAction();
17758         var cb = this.createCB(c);
17759         supr.setWidth.call(this, w, a, d, cb, e);
17760         if(!a){
17761             cb();
17762         }
17763     },
17764
17765     // overridden Element method
17766     setHeight : function(h, a, d, c, e){
17767         this.beforeAction();
17768         var cb = this.createCB(c);
17769         supr.setHeight.call(this, h, a, d, cb, e);
17770         if(!a){
17771             cb();
17772         }
17773     },
17774
17775     // overridden Element method
17776     setBounds : function(x, y, w, h, a, d, c, e){
17777         this.beforeAction();
17778         var cb = this.createCB(c);
17779         if(!a){
17780             this.storeXY([x, y]);
17781             supr.setXY.call(this, [x, y]);
17782             supr.setSize.call(this, w, h, a, d, cb, e);
17783             cb();
17784         }else{
17785             supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
17786         }
17787         return this;
17788     },
17789     
17790     /**
17791      * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
17792      * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
17793      * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
17794      * @param {Number} zindex The new z-index to set
17795      * @return {this} The Layer
17796      */
17797     setZIndex : function(zindex){
17798         this.zindex = zindex;
17799         this.setStyle("z-index", zindex + 2);
17800         if(this.shadow){
17801             this.shadow.setZIndex(zindex + 1);
17802         }
17803         if(this.shim){
17804             this.shim.setStyle("z-index", zindex);
17805         }
17806     }
17807 });
17808 })();/*
17809  * Original code for Roojs - LGPL
17810  * <script type="text/javascript">
17811  */
17812  
17813 /**
17814  * @class Roo.XComponent
17815  * A delayed Element creator...
17816  * Or a way to group chunks of interface together.
17817  * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
17818  *  used in conjunction with XComponent.build() it will create an instance of each element,
17819  *  then call addxtype() to build the User interface.
17820  * 
17821  * Mypart.xyx = new Roo.XComponent({
17822
17823     parent : 'Mypart.xyz', // empty == document.element.!!
17824     order : '001',
17825     name : 'xxxx'
17826     region : 'xxxx'
17827     disabled : function() {} 
17828      
17829     tree : function() { // return an tree of xtype declared components
17830         var MODULE = this;
17831         return 
17832         {
17833             xtype : 'NestedLayoutPanel',
17834             // technicall
17835         }
17836      ]
17837  *})
17838  *
17839  *
17840  * It can be used to build a big heiracy, with parent etc.
17841  * or you can just use this to render a single compoent to a dom element
17842  * MYPART.render(Roo.Element | String(id) | dom_element )
17843  *
17844  *
17845  * Usage patterns.
17846  *
17847  * Classic Roo
17848  *
17849  * Roo is designed primarily as a single page application, so the UI build for a standard interface will
17850  * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
17851  *
17852  * Each sub module is expected to have a parent pointing to the class name of it's parent module.
17853  *
17854  * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
17855  * - if mulitple topModules exist, the last one is defined as the top module.
17856  *
17857  * Embeded Roo
17858  * 
17859  * When the top level or multiple modules are to embedded into a existing HTML page,
17860  * the parent element can container '#id' of the element where the module will be drawn.
17861  *
17862  * Bootstrap Roo
17863  *
17864  * Unlike classic Roo, the bootstrap tends not to be used as a single page.
17865  * it relies more on a include mechanism, where sub modules are included into an outer page.
17866  * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
17867  * 
17868  * Bootstrap Roo Included elements
17869  *
17870  * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
17871  * hence confusing the component builder as it thinks there are multiple top level elements. 
17872  *
17873  * String Over-ride & Translations
17874  *
17875  * Our builder application writes all the strings as _strings and _named_strings. This is to enable the translation of elements,
17876  * and also the 'overlaying of string values - needed when different versions of the same application with different text content
17877  * are needed. @see Roo.XComponent.overlayString  
17878  * 
17879  * 
17880  * 
17881  * @extends Roo.util.Observable
17882  * @constructor
17883  * @param cfg {Object} configuration of component
17884  * 
17885  */
17886 Roo.XComponent = function(cfg) {
17887     Roo.apply(this, cfg);
17888     this.addEvents({ 
17889         /**
17890              * @event built
17891              * Fires when this the componnt is built
17892              * @param {Roo.XComponent} c the component
17893              */
17894         'built' : true
17895         
17896     });
17897     this.region = this.region || 'center'; // default..
17898     Roo.XComponent.register(this);
17899     this.modules = false;
17900     this.el = false; // where the layout goes..
17901     
17902     
17903 }
17904 Roo.extend(Roo.XComponent, Roo.util.Observable, {
17905     /**
17906      * @property el
17907      * The created element (with Roo.factory())
17908      * @type {Roo.Layout}
17909      */
17910     el  : false,
17911     
17912     /**
17913      * @property el
17914      * for BC  - use el in new code
17915      * @type {Roo.Layout}
17916      */
17917     panel : false,
17918     
17919     /**
17920      * @property layout
17921      * for BC  - use el in new code
17922      * @type {Roo.Layout}
17923      */
17924     layout : false,
17925     
17926      /**
17927      * @cfg {Function|boolean} disabled
17928      * If this module is disabled by some rule, return true from the funtion
17929      */
17930     disabled : false,
17931     
17932     /**
17933      * @cfg {String} parent 
17934      * Name of parent element which it get xtype added to..
17935      */
17936     parent: false,
17937     
17938     /**
17939      * @cfg {String} order
17940      * Used to set the order in which elements are created (usefull for multiple tabs)
17941      */
17942     
17943     order : false,
17944     /**
17945      * @cfg {String} name
17946      * String to display while loading.
17947      */
17948     name : false,
17949     /**
17950      * @cfg {String} region
17951      * Region to render component to (defaults to center)
17952      */
17953     region : 'center',
17954     
17955     /**
17956      * @cfg {Array} items
17957      * A single item array - the first element is the root of the tree..
17958      * It's done this way to stay compatible with the Xtype system...
17959      */
17960     items : false,
17961     
17962     /**
17963      * @property _tree
17964      * The method that retuns the tree of parts that make up this compoennt 
17965      * @type {function}
17966      */
17967     _tree  : false,
17968     
17969      /**
17970      * render
17971      * render element to dom or tree
17972      * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
17973      */
17974     
17975     render : function(el)
17976     {
17977         
17978         el = el || false;
17979         var hp = this.parent ? 1 : 0;
17980         Roo.debug &&  Roo.log(this);
17981         
17982         var tree = this._tree ? this._tree() : this.tree();
17983
17984         
17985         if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
17986             // if parent is a '#.....' string, then let's use that..
17987             var ename = this.parent.substr(1);
17988             this.parent = false;
17989             Roo.debug && Roo.log(ename);
17990             switch (ename) {
17991                 case 'bootstrap-body':
17992                     if (typeof(tree.el) != 'undefined' && tree.el == document.body)  {
17993                         // this is the BorderLayout standard?
17994                        this.parent = { el : true };
17995                        break;
17996                     }
17997                     if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype)  > -1)  {
17998                         // need to insert stuff...
17999                         this.parent =  {
18000                              el : new Roo.bootstrap.layout.Border({
18001                                  el : document.body, 
18002                      
18003                                  center: {
18004                                     titlebar: false,
18005                                     autoScroll:false,
18006                                     closeOnTab: true,
18007                                     tabPosition: 'top',
18008                                       //resizeTabs: true,
18009                                     alwaysShowTabs: true,
18010                                     hideTabs: false
18011                                      //minTabWidth: 140
18012                                  }
18013                              })
18014                         
18015                          };
18016                          break;
18017                     }
18018                          
18019                     if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
18020                         this.parent = { el :  new  Roo.bootstrap.Body() };
18021                         Roo.debug && Roo.log("setting el to doc body");
18022                          
18023                     } else {
18024                         throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
18025                     }
18026                     break;
18027                 case 'bootstrap':
18028                     this.parent = { el : true};
18029                     // fall through
18030                 default:
18031                     el = Roo.get(ename);
18032                     if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
18033                         this.parent = { el : true};
18034                     }
18035                     
18036                     break;
18037             }
18038                 
18039             
18040             if (!el && !this.parent) {
18041                 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
18042                 return;
18043             }
18044         }
18045         
18046         Roo.debug && Roo.log("EL:");
18047         Roo.debug && Roo.log(el);
18048         Roo.debug && Roo.log("this.parent.el:");
18049         Roo.debug && Roo.log(this.parent.el);
18050         
18051
18052         // altertive root elements ??? - we need a better way to indicate these.
18053         var is_alt = Roo.XComponent.is_alt ||
18054                     (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
18055                     (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
18056                     (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
18057         
18058         
18059         
18060         if (!this.parent && is_alt) {
18061             //el = Roo.get(document.body);
18062             this.parent = { el : true };
18063         }
18064             
18065             
18066         
18067         if (!this.parent) {
18068             
18069             Roo.debug && Roo.log("no parent - creating one");
18070             
18071             el = el ? Roo.get(el) : false;      
18072             
18073             if (typeof(Roo.BorderLayout) == 'undefined' ) {
18074                 
18075                 this.parent =  {
18076                     el : new Roo.bootstrap.layout.Border({
18077                         el: el || document.body,
18078                     
18079                         center: {
18080                             titlebar: false,
18081                             autoScroll:false,
18082                             closeOnTab: true,
18083                             tabPosition: 'top',
18084                              //resizeTabs: true,
18085                             alwaysShowTabs: false,
18086                             hideTabs: true,
18087                             minTabWidth: 140,
18088                             overflow: 'visible'
18089                          }
18090                      })
18091                 };
18092             } else {
18093             
18094                 // it's a top level one..
18095                 this.parent =  {
18096                     el : new Roo.BorderLayout(el || document.body, {
18097                         center: {
18098                             titlebar: false,
18099                             autoScroll:false,
18100                             closeOnTab: true,
18101                             tabPosition: 'top',
18102                              //resizeTabs: true,
18103                             alwaysShowTabs: el && hp? false :  true,
18104                             hideTabs: el || !hp ? true :  false,
18105                             minTabWidth: 140
18106                          }
18107                     })
18108                 };
18109             }
18110         }
18111         
18112         if (!this.parent.el) {
18113                 // probably an old style ctor, which has been disabled.
18114                 return;
18115
18116         }
18117                 // The 'tree' method is  '_tree now' 
18118             
18119         tree.region = tree.region || this.region;
18120         var is_body = false;
18121         if (this.parent.el === true) {
18122             // bootstrap... - body..
18123             if (el) {
18124                 tree.el = el;
18125             }
18126             this.parent.el = Roo.factory(tree);
18127             is_body = true;
18128         }
18129         
18130         this.el = this.parent.el.addxtype(tree, undefined, is_body);
18131         this.fireEvent('built', this);
18132         
18133         this.panel = this.el;
18134         this.layout = this.panel.layout;
18135         this.parentLayout = this.parent.layout  || false;  
18136          
18137     }
18138     
18139 });
18140
18141 Roo.apply(Roo.XComponent, {
18142     /**
18143      * @property  hideProgress
18144      * true to disable the building progress bar.. usefull on single page renders.
18145      * @type Boolean
18146      */
18147     hideProgress : false,
18148     /**
18149      * @property  buildCompleted
18150      * True when the builder has completed building the interface.
18151      * @type Boolean
18152      */
18153     buildCompleted : false,
18154      
18155     /**
18156      * @property  topModule
18157      * the upper most module - uses document.element as it's constructor.
18158      * @type Object
18159      */
18160      
18161     topModule  : false,
18162       
18163     /**
18164      * @property  modules
18165      * array of modules to be created by registration system.
18166      * @type {Array} of Roo.XComponent
18167      */
18168     
18169     modules : [],
18170     /**
18171      * @property  elmodules
18172      * array of modules to be created by which use #ID 
18173      * @type {Array} of Roo.XComponent
18174      */
18175      
18176     elmodules : [],
18177
18178      /**
18179      * @property  is_alt
18180      * Is an alternative Root - normally used by bootstrap or other systems,
18181      *    where the top element in the tree can wrap 'body' 
18182      * @type {boolean}  (default false)
18183      */
18184      
18185     is_alt : false,
18186     /**
18187      * @property  build_from_html
18188      * Build elements from html - used by bootstrap HTML stuff 
18189      *    - this is cleared after build is completed
18190      * @type {boolean}    (default false)
18191      */
18192      
18193     build_from_html : false,
18194     /**
18195      * Register components to be built later.
18196      *
18197      * This solves the following issues
18198      * - Building is not done on page load, but after an authentication process has occured.
18199      * - Interface elements are registered on page load
18200      * - Parent Interface elements may not be loaded before child, so this handles that..
18201      * 
18202      *
18203      * example:
18204      * 
18205      * MyApp.register({
18206           order : '000001',
18207           module : 'Pman.Tab.projectMgr',
18208           region : 'center',
18209           parent : 'Pman.layout',
18210           disabled : false,  // or use a function..
18211         })
18212      
18213      * * @param {Object} details about module
18214      */
18215     register : function(obj) {
18216                 
18217         Roo.XComponent.event.fireEvent('register', obj);
18218         switch(typeof(obj.disabled) ) {
18219                 
18220             case 'undefined':
18221                 break;
18222             
18223             case 'function':
18224                 if ( obj.disabled() ) {
18225                         return;
18226                 }
18227                 break;
18228             
18229             default:
18230                 if (obj.disabled || obj.region == '#disabled') {
18231                         return;
18232                 }
18233                 break;
18234         }
18235                 
18236         this.modules.push(obj);
18237          
18238     },
18239     /**
18240      * convert a string to an object..
18241      * eg. 'AAA.BBB' -> finds AAA.BBB
18242
18243      */
18244     
18245     toObject : function(str)
18246     {
18247         if (!str || typeof(str) == 'object') {
18248             return str;
18249         }
18250         if (str.substring(0,1) == '#') {
18251             return str;
18252         }
18253
18254         var ar = str.split('.');
18255         var rt, o;
18256         rt = ar.shift();
18257             /** eval:var:o */
18258         try {
18259             eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
18260         } catch (e) {
18261             throw "Module not found : " + str;
18262         }
18263         
18264         if (o === false) {
18265             throw "Module not found : " + str;
18266         }
18267         Roo.each(ar, function(e) {
18268             if (typeof(o[e]) == 'undefined') {
18269                 throw "Module not found : " + str;
18270             }
18271             o = o[e];
18272         });
18273         
18274         return o;
18275         
18276     },
18277     
18278     
18279     /**
18280      * move modules into their correct place in the tree..
18281      * 
18282      */
18283     preBuild : function ()
18284     {
18285         var _t = this;
18286         Roo.each(this.modules , function (obj)
18287         {
18288             Roo.XComponent.event.fireEvent('beforebuild', obj);
18289             
18290             var opar = obj.parent;
18291             try { 
18292                 obj.parent = this.toObject(opar);
18293             } catch(e) {
18294                 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
18295                 return;
18296             }
18297             
18298             if (!obj.parent) {
18299                 Roo.debug && Roo.log("GOT top level module");
18300                 Roo.debug && Roo.log(obj);
18301                 obj.modules = new Roo.util.MixedCollection(false, 
18302                     function(o) { return o.order + '' }
18303                 );
18304                 this.topModule = obj;
18305                 return;
18306             }
18307                         // parent is a string (usually a dom element name..)
18308             if (typeof(obj.parent) == 'string') {
18309                 this.elmodules.push(obj);
18310                 return;
18311             }
18312             if (obj.parent.constructor != Roo.XComponent) {
18313                 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
18314             }
18315             if (!obj.parent.modules) {
18316                 obj.parent.modules = new Roo.util.MixedCollection(false, 
18317                     function(o) { return o.order + '' }
18318                 );
18319             }
18320             if (obj.parent.disabled) {
18321                 obj.disabled = true;
18322             }
18323             obj.parent.modules.add(obj);
18324         }, this);
18325     },
18326     
18327      /**
18328      * make a list of modules to build.
18329      * @return {Array} list of modules. 
18330      */ 
18331     
18332     buildOrder : function()
18333     {
18334         var _this = this;
18335         var cmp = function(a,b) {   
18336             return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
18337         };
18338         if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
18339             throw "No top level modules to build";
18340         }
18341         
18342         // make a flat list in order of modules to build.
18343         var mods = this.topModule ? [ this.topModule ] : [];
18344                 
18345         
18346         // elmodules (is a list of DOM based modules )
18347         Roo.each(this.elmodules, function(e) {
18348             mods.push(e);
18349             if (!this.topModule &&
18350                 typeof(e.parent) == 'string' &&
18351                 e.parent.substring(0,1) == '#' &&
18352                 Roo.get(e.parent.substr(1))
18353                ) {
18354                 
18355                 _this.topModule = e;
18356             }
18357             
18358         });
18359
18360         
18361         // add modules to their parents..
18362         var addMod = function(m) {
18363             Roo.debug && Roo.log("build Order: add: " + m.name);
18364                 
18365             mods.push(m);
18366             if (m.modules && !m.disabled) {
18367                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
18368                 m.modules.keySort('ASC',  cmp );
18369                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
18370     
18371                 m.modules.each(addMod);
18372             } else {
18373                 Roo.debug && Roo.log("build Order: no child modules");
18374             }
18375             // not sure if this is used any more..
18376             if (m.finalize) {
18377                 m.finalize.name = m.name + " (clean up) ";
18378                 mods.push(m.finalize);
18379             }
18380             
18381         }
18382         if (this.topModule && this.topModule.modules) { 
18383             this.topModule.modules.keySort('ASC',  cmp );
18384             this.topModule.modules.each(addMod);
18385         } 
18386         return mods;
18387     },
18388     
18389      /**
18390      * Build the registered modules.
18391      * @param {Object} parent element.
18392      * @param {Function} optional method to call after module has been added.
18393      * 
18394      */ 
18395    
18396     build : function(opts) 
18397     {
18398         
18399         if (typeof(opts) != 'undefined') {
18400             Roo.apply(this,opts);
18401         }
18402         
18403         this.preBuild();
18404         var mods = this.buildOrder();
18405       
18406         //this.allmods = mods;
18407         //Roo.debug && Roo.log(mods);
18408         //return;
18409         if (!mods.length) { // should not happen
18410             throw "NO modules!!!";
18411         }
18412         
18413         
18414         var msg = "Building Interface...";
18415         // flash it up as modal - so we store the mask!?
18416         if (!this.hideProgress && Roo.MessageBox) {
18417             Roo.MessageBox.show({ title: 'loading' });
18418             Roo.MessageBox.show({
18419                title: "Please wait...",
18420                msg: msg,
18421                width:450,
18422                progress:true,
18423                buttons : false,
18424                closable:false,
18425                modal: false
18426               
18427             });
18428         }
18429         var total = mods.length;
18430         
18431         var _this = this;
18432         var progressRun = function() {
18433             if (!mods.length) {
18434                 Roo.debug && Roo.log('hide?');
18435                 if (!this.hideProgress && Roo.MessageBox) {
18436                     Roo.MessageBox.hide();
18437                 }
18438                 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
18439                 
18440                 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
18441                 
18442                 // THE END...
18443                 return false;   
18444             }
18445             
18446             var m = mods.shift();
18447             
18448             
18449             Roo.debug && Roo.log(m);
18450             // not sure if this is supported any more.. - modules that are are just function
18451             if (typeof(m) == 'function') { 
18452                 m.call(this);
18453                 return progressRun.defer(10, _this);
18454             } 
18455             
18456             
18457             msg = "Building Interface " + (total  - mods.length) + 
18458                     " of " + total + 
18459                     (m.name ? (' - ' + m.name) : '');
18460                         Roo.debug && Roo.log(msg);
18461             if (!_this.hideProgress &&  Roo.MessageBox) { 
18462                 Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
18463             }
18464             
18465          
18466             // is the module disabled?
18467             var disabled = (typeof(m.disabled) == 'function') ?
18468                 m.disabled.call(m.module.disabled) : m.disabled;    
18469             
18470             
18471             if (disabled) {
18472                 return progressRun(); // we do not update the display!
18473             }
18474             
18475             // now build 
18476             
18477                         
18478                         
18479             m.render();
18480             // it's 10 on top level, and 1 on others??? why...
18481             return progressRun.defer(10, _this);
18482              
18483         }
18484         progressRun.defer(1, _this);
18485      
18486         
18487         
18488     },
18489     /**
18490      * Overlay a set of modified strings onto a component
18491      * This is dependant on our builder exporting the strings and 'named strings' elements.
18492      * 
18493      * @param {Object} element to overlay on - eg. Pman.Dialog.Login
18494      * @param {Object} associative array of 'named' string and it's new value.
18495      * 
18496      */
18497         overlayStrings : function( component, strings )
18498     {
18499         if (typeof(component['_named_strings']) == 'undefined') {
18500             throw "ERROR: component does not have _named_strings";
18501         }
18502         for ( var k in strings ) {
18503             var md = typeof(component['_named_strings'][k]) == 'undefined' ? false : component['_named_strings'][k];
18504             if (md !== false) {
18505                 component['_strings'][md] = strings[k];
18506             } else {
18507                 Roo.log('could not find named string: ' + k + ' in');
18508                 Roo.log(component);
18509             }
18510             
18511         }
18512         
18513     },
18514     
18515         
18516         /**
18517          * Event Object.
18518          *
18519          *
18520          */
18521         event: false, 
18522     /**
18523          * wrapper for event.on - aliased later..  
18524          * Typically use to register a event handler for register:
18525          *
18526          * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
18527          *
18528          */
18529     on : false
18530    
18531     
18532     
18533 });
18534
18535 Roo.XComponent.event = new Roo.util.Observable({
18536                 events : { 
18537                         /**
18538                          * @event register
18539                          * Fires when an Component is registered,
18540                          * set the disable property on the Component to stop registration.
18541                          * @param {Roo.XComponent} c the component being registerd.
18542                          * 
18543                          */
18544                         'register' : true,
18545             /**
18546                          * @event beforebuild
18547                          * Fires before each Component is built
18548                          * can be used to apply permissions.
18549                          * @param {Roo.XComponent} c the component being registerd.
18550                          * 
18551                          */
18552                         'beforebuild' : true,
18553                         /**
18554                          * @event buildcomplete
18555                          * Fires on the top level element when all elements have been built
18556                          * @param {Roo.XComponent} the top level component.
18557                          */
18558                         'buildcomplete' : true
18559                         
18560                 }
18561 });
18562
18563 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event); 
18564  //
18565  /**
18566  * marked - a markdown parser
18567  * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
18568  * https://github.com/chjj/marked
18569  */
18570
18571
18572 /**
18573  *
18574  * Roo.Markdown - is a very crude wrapper around marked..
18575  *
18576  * usage:
18577  * 
18578  * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
18579  * 
18580  * Note: move the sample code to the bottom of this
18581  * file before uncommenting it.
18582  *
18583  */
18584
18585 Roo.Markdown = {};
18586 Roo.Markdown.toHtml = function(text) {
18587     
18588     var c = new Roo.Markdown.marked.setOptions({
18589             renderer: new Roo.Markdown.marked.Renderer(),
18590             gfm: true,
18591             tables: true,
18592             breaks: false,
18593             pedantic: false,
18594             sanitize: false,
18595             smartLists: true,
18596             smartypants: false
18597           });
18598     // A FEW HACKS!!?
18599     
18600     text = text.replace(/\\\n/g,' ');
18601     return Roo.Markdown.marked(text);
18602 };
18603 //
18604 // converter
18605 //
18606 // Wraps all "globals" so that the only thing
18607 // exposed is makeHtml().
18608 //
18609 (function() {
18610     
18611      /**
18612          * eval:var:escape
18613          * eval:var:unescape
18614          * eval:var:replace
18615          */
18616       
18617     /**
18618      * Helpers
18619      */
18620     
18621     var escape = function (html, encode) {
18622       return html
18623         .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&amp;')
18624         .replace(/</g, '&lt;')
18625         .replace(/>/g, '&gt;')
18626         .replace(/"/g, '&quot;')
18627         .replace(/'/g, '&#39;');
18628     }
18629     
18630     var unescape = function (html) {
18631         // explicitly match decimal, hex, and named HTML entities 
18632       return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
18633         n = n.toLowerCase();
18634         if (n === 'colon') { return ':'; }
18635         if (n.charAt(0) === '#') {
18636           return n.charAt(1) === 'x'
18637             ? String.fromCharCode(parseInt(n.substring(2), 16))
18638             : String.fromCharCode(+n.substring(1));
18639         }
18640         return '';
18641       });
18642     }
18643     
18644     var replace = function (regex, opt) {
18645       regex = regex.source;
18646       opt = opt || '';
18647       return function self(name, val) {
18648         if (!name) { return new RegExp(regex, opt); }
18649         val = val.source || val;
18650         val = val.replace(/(^|[^\[])\^/g, '$1');
18651         regex = regex.replace(name, val);
18652         return self;
18653       };
18654     }
18655
18656
18657          /**
18658          * eval:var:noop
18659     */
18660     var noop = function () {}
18661     noop.exec = noop;
18662     
18663          /**
18664          * eval:var:merge
18665     */
18666     var merge = function (obj) {
18667       var i = 1
18668         , target
18669         , key;
18670     
18671       for (; i < arguments.length; i++) {
18672         target = arguments[i];
18673         for (key in target) {
18674           if (Object.prototype.hasOwnProperty.call(target, key)) {
18675             obj[key] = target[key];
18676           }
18677         }
18678       }
18679     
18680       return obj;
18681     }
18682     
18683     
18684     /**
18685      * Block-Level Grammar
18686      */
18687     
18688     
18689     
18690     
18691     var block = {
18692       newline: /^\n+/,
18693       code: /^( {4}[^\n]+\n*)+/,
18694       fences: noop,
18695       hr: /^( *[-*_]){3,} *(?:\n+|$)/,
18696       heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
18697       nptable: noop,
18698       lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
18699       blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
18700       list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
18701       html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
18702       def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
18703       table: noop,
18704       paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
18705       text: /^[^\n]+/
18706     };
18707     
18708     block.bullet = /(?:[*+-]|\d+\.)/;
18709     block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
18710     block.item = replace(block.item, 'gm')
18711       (/bull/g, block.bullet)
18712       ();
18713     
18714     block.list = replace(block.list)
18715       (/bull/g, block.bullet)
18716       ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
18717       ('def', '\\n+(?=' + block.def.source + ')')
18718       ();
18719     
18720     block.blockquote = replace(block.blockquote)
18721       ('def', block.def)
18722       ();
18723     
18724     block._tag = '(?!(?:'
18725       + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
18726       + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
18727       + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
18728     
18729     block.html = replace(block.html)
18730       ('comment', /<!--[\s\S]*?-->/)
18731       ('closed', /<(tag)[\s\S]+?<\/\1>/)
18732       ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
18733       (/tag/g, block._tag)
18734       ();
18735     
18736     block.paragraph = replace(block.paragraph)
18737       ('hr', block.hr)
18738       ('heading', block.heading)
18739       ('lheading', block.lheading)
18740       ('blockquote', block.blockquote)
18741       ('tag', '<' + block._tag)
18742       ('def', block.def)
18743       ();
18744     
18745     /**
18746      * Normal Block Grammar
18747      */
18748     
18749     block.normal = merge({}, block);
18750     
18751     /**
18752      * GFM Block Grammar
18753      */
18754     
18755     block.gfm = merge({}, block.normal, {
18756       fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
18757       paragraph: /^/,
18758       heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
18759     });
18760     
18761     block.gfm.paragraph = replace(block.paragraph)
18762       ('(?!', '(?!'
18763         + block.gfm.fences.source.replace('\\1', '\\2') + '|'
18764         + block.list.source.replace('\\1', '\\3') + '|')
18765       ();
18766     
18767     /**
18768      * GFM + Tables Block Grammar
18769      */
18770     
18771     block.tables = merge({}, block.gfm, {
18772       nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
18773       table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
18774     });
18775     
18776     /**
18777      * Block Lexer
18778      */
18779     
18780     var Lexer = function (options) {
18781       this.tokens = [];
18782       this.tokens.links = {};
18783       this.options = options || marked.defaults;
18784       this.rules = block.normal;
18785     
18786       if (this.options.gfm) {
18787         if (this.options.tables) {
18788           this.rules = block.tables;
18789         } else {
18790           this.rules = block.gfm;
18791         }
18792       }
18793     }
18794     
18795     /**
18796      * Expose Block Rules
18797      */
18798     
18799     Lexer.rules = block;
18800     
18801     /**
18802      * Static Lex Method
18803      */
18804     
18805     Lexer.lex = function(src, options) {
18806       var lexer = new Lexer(options);
18807       return lexer.lex(src);
18808     };
18809     
18810     /**
18811      * Preprocessing
18812      */
18813     
18814     Lexer.prototype.lex = function(src) {
18815       src = src
18816         .replace(/\r\n|\r/g, '\n')
18817         .replace(/\t/g, '    ')
18818         .replace(/\u00a0/g, ' ')
18819         .replace(/\u2424/g, '\n');
18820     
18821       return this.token(src, true);
18822     };
18823     
18824     /**
18825      * Lexing
18826      */
18827     
18828     Lexer.prototype.token = function(src, top, bq) {
18829       var src = src.replace(/^ +$/gm, '')
18830         , next
18831         , loose
18832         , cap
18833         , bull
18834         , b
18835         , item
18836         , space
18837         , i
18838         , l;
18839     
18840       while (src) {
18841         // newline
18842         if (cap = this.rules.newline.exec(src)) {
18843           src = src.substring(cap[0].length);
18844           if (cap[0].length > 1) {
18845             this.tokens.push({
18846               type: 'space'
18847             });
18848           }
18849         }
18850     
18851         // code
18852         if (cap = this.rules.code.exec(src)) {
18853           src = src.substring(cap[0].length);
18854           cap = cap[0].replace(/^ {4}/gm, '');
18855           this.tokens.push({
18856             type: 'code',
18857             text: !this.options.pedantic
18858               ? cap.replace(/\n+$/, '')
18859               : cap
18860           });
18861           continue;
18862         }
18863     
18864         // fences (gfm)
18865         if (cap = this.rules.fences.exec(src)) {
18866           src = src.substring(cap[0].length);
18867           this.tokens.push({
18868             type: 'code',
18869             lang: cap[2],
18870             text: cap[3] || ''
18871           });
18872           continue;
18873         }
18874     
18875         // heading
18876         if (cap = this.rules.heading.exec(src)) {
18877           src = src.substring(cap[0].length);
18878           this.tokens.push({
18879             type: 'heading',
18880             depth: cap[1].length,
18881             text: cap[2]
18882           });
18883           continue;
18884         }
18885     
18886         // table no leading pipe (gfm)
18887         if (top && (cap = this.rules.nptable.exec(src))) {
18888           src = src.substring(cap[0].length);
18889     
18890           item = {
18891             type: 'table',
18892             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
18893             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
18894             cells: cap[3].replace(/\n$/, '').split('\n')
18895           };
18896     
18897           for (i = 0; i < item.align.length; i++) {
18898             if (/^ *-+: *$/.test(item.align[i])) {
18899               item.align[i] = 'right';
18900             } else if (/^ *:-+: *$/.test(item.align[i])) {
18901               item.align[i] = 'center';
18902             } else if (/^ *:-+ *$/.test(item.align[i])) {
18903               item.align[i] = 'left';
18904             } else {
18905               item.align[i] = null;
18906             }
18907           }
18908     
18909           for (i = 0; i < item.cells.length; i++) {
18910             item.cells[i] = item.cells[i].split(/ *\| */);
18911           }
18912     
18913           this.tokens.push(item);
18914     
18915           continue;
18916         }
18917     
18918         // lheading
18919         if (cap = this.rules.lheading.exec(src)) {
18920           src = src.substring(cap[0].length);
18921           this.tokens.push({
18922             type: 'heading',
18923             depth: cap[2] === '=' ? 1 : 2,
18924             text: cap[1]
18925           });
18926           continue;
18927         }
18928     
18929         // hr
18930         if (cap = this.rules.hr.exec(src)) {
18931           src = src.substring(cap[0].length);
18932           this.tokens.push({
18933             type: 'hr'
18934           });
18935           continue;
18936         }
18937     
18938         // blockquote
18939         if (cap = this.rules.blockquote.exec(src)) {
18940           src = src.substring(cap[0].length);
18941     
18942           this.tokens.push({
18943             type: 'blockquote_start'
18944           });
18945     
18946           cap = cap[0].replace(/^ *> ?/gm, '');
18947     
18948           // Pass `top` to keep the current
18949           // "toplevel" state. This is exactly
18950           // how markdown.pl works.
18951           this.token(cap, top, true);
18952     
18953           this.tokens.push({
18954             type: 'blockquote_end'
18955           });
18956     
18957           continue;
18958         }
18959     
18960         // list
18961         if (cap = this.rules.list.exec(src)) {
18962           src = src.substring(cap[0].length);
18963           bull = cap[2];
18964     
18965           this.tokens.push({
18966             type: 'list_start',
18967             ordered: bull.length > 1
18968           });
18969     
18970           // Get each top-level item.
18971           cap = cap[0].match(this.rules.item);
18972     
18973           next = false;
18974           l = cap.length;
18975           i = 0;
18976     
18977           for (; i < l; i++) {
18978             item = cap[i];
18979     
18980             // Remove the list item's bullet
18981             // so it is seen as the next token.
18982             space = item.length;
18983             item = item.replace(/^ *([*+-]|\d+\.) +/, '');
18984     
18985             // Outdent whatever the
18986             // list item contains. Hacky.
18987             if (~item.indexOf('\n ')) {
18988               space -= item.length;
18989               item = !this.options.pedantic
18990                 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
18991                 : item.replace(/^ {1,4}/gm, '');
18992             }
18993     
18994             // Determine whether the next list item belongs here.
18995             // Backpedal if it does not belong in this list.
18996             if (this.options.smartLists && i !== l - 1) {
18997               b = block.bullet.exec(cap[i + 1])[0];
18998               if (bull !== b && !(bull.length > 1 && b.length > 1)) {
18999                 src = cap.slice(i + 1).join('\n') + src;
19000                 i = l - 1;
19001               }
19002             }
19003     
19004             // Determine whether item is loose or not.
19005             // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
19006             // for discount behavior.
19007             loose = next || /\n\n(?!\s*$)/.test(item);
19008             if (i !== l - 1) {
19009               next = item.charAt(item.length - 1) === '\n';
19010               if (!loose) { loose = next; }
19011             }
19012     
19013             this.tokens.push({
19014               type: loose
19015                 ? 'loose_item_start'
19016                 : 'list_item_start'
19017             });
19018     
19019             // Recurse.
19020             this.token(item, false, bq);
19021     
19022             this.tokens.push({
19023               type: 'list_item_end'
19024             });
19025           }
19026     
19027           this.tokens.push({
19028             type: 'list_end'
19029           });
19030     
19031           continue;
19032         }
19033     
19034         // html
19035         if (cap = this.rules.html.exec(src)) {
19036           src = src.substring(cap[0].length);
19037           this.tokens.push({
19038             type: this.options.sanitize
19039               ? 'paragraph'
19040               : 'html',
19041             pre: !this.options.sanitizer
19042               && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
19043             text: cap[0]
19044           });
19045           continue;
19046         }
19047     
19048         // def
19049         if ((!bq && top) && (cap = this.rules.def.exec(src))) {
19050           src = src.substring(cap[0].length);
19051           this.tokens.links[cap[1].toLowerCase()] = {
19052             href: cap[2],
19053             title: cap[3]
19054           };
19055           continue;
19056         }
19057     
19058         // table (gfm)
19059         if (top && (cap = this.rules.table.exec(src))) {
19060           src = src.substring(cap[0].length);
19061     
19062           item = {
19063             type: 'table',
19064             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
19065             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
19066             cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
19067           };
19068     
19069           for (i = 0; i < item.align.length; i++) {
19070             if (/^ *-+: *$/.test(item.align[i])) {
19071               item.align[i] = 'right';
19072             } else if (/^ *:-+: *$/.test(item.align[i])) {
19073               item.align[i] = 'center';
19074             } else if (/^ *:-+ *$/.test(item.align[i])) {
19075               item.align[i] = 'left';
19076             } else {
19077               item.align[i] = null;
19078             }
19079           }
19080     
19081           for (i = 0; i < item.cells.length; i++) {
19082             item.cells[i] = item.cells[i]
19083               .replace(/^ *\| *| *\| *$/g, '')
19084               .split(/ *\| */);
19085           }
19086     
19087           this.tokens.push(item);
19088     
19089           continue;
19090         }
19091     
19092         // top-level paragraph
19093         if (top && (cap = this.rules.paragraph.exec(src))) {
19094           src = src.substring(cap[0].length);
19095           this.tokens.push({
19096             type: 'paragraph',
19097             text: cap[1].charAt(cap[1].length - 1) === '\n'
19098               ? cap[1].slice(0, -1)
19099               : cap[1]
19100           });
19101           continue;
19102         }
19103     
19104         // text
19105         if (cap = this.rules.text.exec(src)) {
19106           // Top-level should never reach here.
19107           src = src.substring(cap[0].length);
19108           this.tokens.push({
19109             type: 'text',
19110             text: cap[0]
19111           });
19112           continue;
19113         }
19114     
19115         if (src) {
19116           throw new
19117             Error('Infinite loop on byte: ' + src.charCodeAt(0));
19118         }
19119       }
19120     
19121       return this.tokens;
19122     };
19123     
19124     /**
19125      * Inline-Level Grammar
19126      */
19127     
19128     var inline = {
19129       escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
19130       autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
19131       url: noop,
19132       tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
19133       link: /^!?\[(inside)\]\(href\)/,
19134       reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
19135       nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
19136       strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
19137       em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
19138       code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
19139       br: /^ {2,}\n(?!\s*$)/,
19140       del: noop,
19141       text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
19142     };
19143     
19144     inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
19145     inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
19146     
19147     inline.link = replace(inline.link)
19148       ('inside', inline._inside)
19149       ('href', inline._href)
19150       ();
19151     
19152     inline.reflink = replace(inline.reflink)
19153       ('inside', inline._inside)
19154       ();
19155     
19156     /**
19157      * Normal Inline Grammar
19158      */
19159     
19160     inline.normal = merge({}, inline);
19161     
19162     /**
19163      * Pedantic Inline Grammar
19164      */
19165     
19166     inline.pedantic = merge({}, inline.normal, {
19167       strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
19168       em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
19169     });
19170     
19171     /**
19172      * GFM Inline Grammar
19173      */
19174     
19175     inline.gfm = merge({}, inline.normal, {
19176       escape: replace(inline.escape)('])', '~|])')(),
19177       url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
19178       del: /^~~(?=\S)([\s\S]*?\S)~~/,
19179       text: replace(inline.text)
19180         (']|', '~]|')
19181         ('|', '|https?://|')
19182         ()
19183     });
19184     
19185     /**
19186      * GFM + Line Breaks Inline Grammar
19187      */
19188     
19189     inline.breaks = merge({}, inline.gfm, {
19190       br: replace(inline.br)('{2,}', '*')(),
19191       text: replace(inline.gfm.text)('{2,}', '*')()
19192     });
19193     
19194     /**
19195      * Inline Lexer & Compiler
19196      */
19197     
19198     var InlineLexer  = function (links, options) {
19199       this.options = options || marked.defaults;
19200       this.links = links;
19201       this.rules = inline.normal;
19202       this.renderer = this.options.renderer || new Renderer;
19203       this.renderer.options = this.options;
19204     
19205       if (!this.links) {
19206         throw new
19207           Error('Tokens array requires a `links` property.');
19208       }
19209     
19210       if (this.options.gfm) {
19211         if (this.options.breaks) {
19212           this.rules = inline.breaks;
19213         } else {
19214           this.rules = inline.gfm;
19215         }
19216       } else if (this.options.pedantic) {
19217         this.rules = inline.pedantic;
19218       }
19219     }
19220     
19221     /**
19222      * Expose Inline Rules
19223      */
19224     
19225     InlineLexer.rules = inline;
19226     
19227     /**
19228      * Static Lexing/Compiling Method
19229      */
19230     
19231     InlineLexer.output = function(src, links, options) {
19232       var inline = new InlineLexer(links, options);
19233       return inline.output(src);
19234     };
19235     
19236     /**
19237      * Lexing/Compiling
19238      */
19239     
19240     InlineLexer.prototype.output = function(src) {
19241       var out = ''
19242         , link
19243         , text
19244         , href
19245         , cap;
19246     
19247       while (src) {
19248         // escape
19249         if (cap = this.rules.escape.exec(src)) {
19250           src = src.substring(cap[0].length);
19251           out += cap[1];
19252           continue;
19253         }
19254     
19255         // autolink
19256         if (cap = this.rules.autolink.exec(src)) {
19257           src = src.substring(cap[0].length);
19258           if (cap[2] === '@') {
19259             text = cap[1].charAt(6) === ':'
19260               ? this.mangle(cap[1].substring(7))
19261               : this.mangle(cap[1]);
19262             href = this.mangle('mailto:') + text;
19263           } else {
19264             text = escape(cap[1]);
19265             href = text;
19266           }
19267           out += this.renderer.link(href, null, text);
19268           continue;
19269         }
19270     
19271         // url (gfm)
19272         if (!this.inLink && (cap = this.rules.url.exec(src))) {
19273           src = src.substring(cap[0].length);
19274           text = escape(cap[1]);
19275           href = text;
19276           out += this.renderer.link(href, null, text);
19277           continue;
19278         }
19279     
19280         // tag
19281         if (cap = this.rules.tag.exec(src)) {
19282           if (!this.inLink && /^<a /i.test(cap[0])) {
19283             this.inLink = true;
19284           } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
19285             this.inLink = false;
19286           }
19287           src = src.substring(cap[0].length);
19288           out += this.options.sanitize
19289             ? this.options.sanitizer
19290               ? this.options.sanitizer(cap[0])
19291               : escape(cap[0])
19292             : cap[0];
19293           continue;
19294         }
19295     
19296         // link
19297         if (cap = this.rules.link.exec(src)) {
19298           src = src.substring(cap[0].length);
19299           this.inLink = true;
19300           out += this.outputLink(cap, {
19301             href: cap[2],
19302             title: cap[3]
19303           });
19304           this.inLink = false;
19305           continue;
19306         }
19307     
19308         // reflink, nolink
19309         if ((cap = this.rules.reflink.exec(src))
19310             || (cap = this.rules.nolink.exec(src))) {
19311           src = src.substring(cap[0].length);
19312           link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
19313           link = this.links[link.toLowerCase()];
19314           if (!link || !link.href) {
19315             out += cap[0].charAt(0);
19316             src = cap[0].substring(1) + src;
19317             continue;
19318           }
19319           this.inLink = true;
19320           out += this.outputLink(cap, link);
19321           this.inLink = false;
19322           continue;
19323         }
19324     
19325         // strong
19326         if (cap = this.rules.strong.exec(src)) {
19327           src = src.substring(cap[0].length);
19328           out += this.renderer.strong(this.output(cap[2] || cap[1]));
19329           continue;
19330         }
19331     
19332         // em
19333         if (cap = this.rules.em.exec(src)) {
19334           src = src.substring(cap[0].length);
19335           out += this.renderer.em(this.output(cap[2] || cap[1]));
19336           continue;
19337         }
19338     
19339         // code
19340         if (cap = this.rules.code.exec(src)) {
19341           src = src.substring(cap[0].length);
19342           out += this.renderer.codespan(escape(cap[2], true));
19343           continue;
19344         }
19345     
19346         // br
19347         if (cap = this.rules.br.exec(src)) {
19348           src = src.substring(cap[0].length);
19349           out += this.renderer.br();
19350           continue;
19351         }
19352     
19353         // del (gfm)
19354         if (cap = this.rules.del.exec(src)) {
19355           src = src.substring(cap[0].length);
19356           out += this.renderer.del(this.output(cap[1]));
19357           continue;
19358         }
19359     
19360         // text
19361         if (cap = this.rules.text.exec(src)) {
19362           src = src.substring(cap[0].length);
19363           out += this.renderer.text(escape(this.smartypants(cap[0])));
19364           continue;
19365         }
19366     
19367         if (src) {
19368           throw new
19369             Error('Infinite loop on byte: ' + src.charCodeAt(0));
19370         }
19371       }
19372     
19373       return out;
19374     };
19375     
19376     /**
19377      * Compile Link
19378      */
19379     
19380     InlineLexer.prototype.outputLink = function(cap, link) {
19381       var href = escape(link.href)
19382         , title = link.title ? escape(link.title) : null;
19383     
19384       return cap[0].charAt(0) !== '!'
19385         ? this.renderer.link(href, title, this.output(cap[1]))
19386         : this.renderer.image(href, title, escape(cap[1]));
19387     };
19388     
19389     /**
19390      * Smartypants Transformations
19391      */
19392     
19393     InlineLexer.prototype.smartypants = function(text) {
19394       if (!this.options.smartypants)  { return text; }
19395       return text
19396         // em-dashes
19397         .replace(/---/g, '\u2014')
19398         // en-dashes
19399         .replace(/--/g, '\u2013')
19400         // opening singles
19401         .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
19402         // closing singles & apostrophes
19403         .replace(/'/g, '\u2019')
19404         // opening doubles
19405         .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
19406         // closing doubles
19407         .replace(/"/g, '\u201d')
19408         // ellipses
19409         .replace(/\.{3}/g, '\u2026');
19410     };
19411     
19412     /**
19413      * Mangle Links
19414      */
19415     
19416     InlineLexer.prototype.mangle = function(text) {
19417       if (!this.options.mangle) { return text; }
19418       var out = ''
19419         , l = text.length
19420         , i = 0
19421         , ch;
19422     
19423       for (; i < l; i++) {
19424         ch = text.charCodeAt(i);
19425         if (Math.random() > 0.5) {
19426           ch = 'x' + ch.toString(16);
19427         }
19428         out += '&#' + ch + ';';
19429       }
19430     
19431       return out;
19432     };
19433     
19434     /**
19435      * Renderer
19436      */
19437     
19438      /**
19439          * eval:var:Renderer
19440     */
19441     
19442     var Renderer   = function (options) {
19443       this.options = options || {};
19444     }
19445     
19446     Renderer.prototype.code = function(code, lang, escaped) {
19447       if (this.options.highlight) {
19448         var out = this.options.highlight(code, lang);
19449         if (out != null && out !== code) {
19450           escaped = true;
19451           code = out;
19452         }
19453       } else {
19454             // hack!!! - it's already escapeD?
19455             escaped = true;
19456       }
19457     
19458       if (!lang) {
19459         return '<pre><code>'
19460           + (escaped ? code : escape(code, true))
19461           + '\n</code></pre>';
19462       }
19463     
19464       return '<pre><code class="'
19465         + this.options.langPrefix
19466         + escape(lang, true)
19467         + '">'
19468         + (escaped ? code : escape(code, true))
19469         + '\n</code></pre>\n';
19470     };
19471     
19472     Renderer.prototype.blockquote = function(quote) {
19473       return '<blockquote>\n' + quote + '</blockquote>\n';
19474     };
19475     
19476     Renderer.prototype.html = function(html) {
19477       return html;
19478     };
19479     
19480     Renderer.prototype.heading = function(text, level, raw) {
19481       return '<h'
19482         + level
19483         + ' id="'
19484         + this.options.headerPrefix
19485         + raw.toLowerCase().replace(/[^\w]+/g, '-')
19486         + '">'
19487         + text
19488         + '</h'
19489         + level
19490         + '>\n';
19491     };
19492     
19493     Renderer.prototype.hr = function() {
19494       return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
19495     };
19496     
19497     Renderer.prototype.list = function(body, ordered) {
19498       var type = ordered ? 'ol' : 'ul';
19499       return '<' + type + '>\n' + body + '</' + type + '>\n';
19500     };
19501     
19502     Renderer.prototype.listitem = function(text) {
19503       return '<li>' + text + '</li>\n';
19504     };
19505     
19506     Renderer.prototype.paragraph = function(text) {
19507       return '<p>' + text + '</p>\n';
19508     };
19509     
19510     Renderer.prototype.table = function(header, body) {
19511       return '<table class="table table-striped">\n'
19512         + '<thead>\n'
19513         + header
19514         + '</thead>\n'
19515         + '<tbody>\n'
19516         + body
19517         + '</tbody>\n'
19518         + '</table>\n';
19519     };
19520     
19521     Renderer.prototype.tablerow = function(content) {
19522       return '<tr>\n' + content + '</tr>\n';
19523     };
19524     
19525     Renderer.prototype.tablecell = function(content, flags) {
19526       var type = flags.header ? 'th' : 'td';
19527       var tag = flags.align
19528         ? '<' + type + ' style="text-align:' + flags.align + '">'
19529         : '<' + type + '>';
19530       return tag + content + '</' + type + '>\n';
19531     };
19532     
19533     // span level renderer
19534     Renderer.prototype.strong = function(text) {
19535       return '<strong>' + text + '</strong>';
19536     };
19537     
19538     Renderer.prototype.em = function(text) {
19539       return '<em>' + text + '</em>';
19540     };
19541     
19542     Renderer.prototype.codespan = function(text) {
19543       return '<code>' + text + '</code>';
19544     };
19545     
19546     Renderer.prototype.br = function() {
19547       return this.options.xhtml ? '<br/>' : '<br>';
19548     };
19549     
19550     Renderer.prototype.del = function(text) {
19551       return '<del>' + text + '</del>';
19552     };
19553     
19554     Renderer.prototype.link = function(href, title, text) {
19555       if (this.options.sanitize) {
19556         try {
19557           var prot = decodeURIComponent(unescape(href))
19558             .replace(/[^\w:]/g, '')
19559             .toLowerCase();
19560         } catch (e) {
19561           return '';
19562         }
19563         if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
19564           return '';
19565         }
19566       }
19567       var out = '<a href="' + href + '"';
19568       if (title) {
19569         out += ' title="' + title + '"';
19570       }
19571       out += '>' + text + '</a>';
19572       return out;
19573     };
19574     
19575     Renderer.prototype.image = function(href, title, text) {
19576       var out = '<img src="' + href + '" alt="' + text + '"';
19577       if (title) {
19578         out += ' title="' + title + '"';
19579       }
19580       out += this.options.xhtml ? '/>' : '>';
19581       return out;
19582     };
19583     
19584     Renderer.prototype.text = function(text) {
19585       return text;
19586     };
19587     
19588     /**
19589      * Parsing & Compiling
19590      */
19591          /**
19592          * eval:var:Parser
19593     */
19594     
19595     var Parser= function (options) {
19596       this.tokens = [];
19597       this.token = null;
19598       this.options = options || marked.defaults;
19599       this.options.renderer = this.options.renderer || new Renderer;
19600       this.renderer = this.options.renderer;
19601       this.renderer.options = this.options;
19602     }
19603     
19604     /**
19605      * Static Parse Method
19606      */
19607     
19608     Parser.parse = function(src, options, renderer) {
19609       var parser = new Parser(options, renderer);
19610       return parser.parse(src);
19611     };
19612     
19613     /**
19614      * Parse Loop
19615      */
19616     
19617     Parser.prototype.parse = function(src) {
19618       this.inline = new InlineLexer(src.links, this.options, this.renderer);
19619       this.tokens = src.reverse();
19620     
19621       var out = '';
19622       while (this.next()) {
19623         out += this.tok();
19624       }
19625     
19626       return out;
19627     };
19628     
19629     /**
19630      * Next Token
19631      */
19632     
19633     Parser.prototype.next = function() {
19634       return this.token = this.tokens.pop();
19635     };
19636     
19637     /**
19638      * Preview Next Token
19639      */
19640     
19641     Parser.prototype.peek = function() {
19642       return this.tokens[this.tokens.length - 1] || 0;
19643     };
19644     
19645     /**
19646      * Parse Text Tokens
19647      */
19648     
19649     Parser.prototype.parseText = function() {
19650       var body = this.token.text;
19651     
19652       while (this.peek().type === 'text') {
19653         body += '\n' + this.next().text;
19654       }
19655     
19656       return this.inline.output(body);
19657     };
19658     
19659     /**
19660      * Parse Current Token
19661      */
19662     
19663     Parser.prototype.tok = function() {
19664       switch (this.token.type) {
19665         case 'space': {
19666           return '';
19667         }
19668         case 'hr': {
19669           return this.renderer.hr();
19670         }
19671         case 'heading': {
19672           return this.renderer.heading(
19673             this.inline.output(this.token.text),
19674             this.token.depth,
19675             this.token.text);
19676         }
19677         case 'code': {
19678           return this.renderer.code(this.token.text,
19679             this.token.lang,
19680             this.token.escaped);
19681         }
19682         case 'table': {
19683           var header = ''
19684             , body = ''
19685             , i
19686             , row
19687             , cell
19688             , flags
19689             , j;
19690     
19691           // header
19692           cell = '';
19693           for (i = 0; i < this.token.header.length; i++) {
19694             flags = { header: true, align: this.token.align[i] };
19695             cell += this.renderer.tablecell(
19696               this.inline.output(this.token.header[i]),
19697               { header: true, align: this.token.align[i] }
19698             );
19699           }
19700           header += this.renderer.tablerow(cell);
19701     
19702           for (i = 0; i < this.token.cells.length; i++) {
19703             row = this.token.cells[i];
19704     
19705             cell = '';
19706             for (j = 0; j < row.length; j++) {
19707               cell += this.renderer.tablecell(
19708                 this.inline.output(row[j]),
19709                 { header: false, align: this.token.align[j] }
19710               );
19711             }
19712     
19713             body += this.renderer.tablerow(cell);
19714           }
19715           return this.renderer.table(header, body);
19716         }
19717         case 'blockquote_start': {
19718           var body = '';
19719     
19720           while (this.next().type !== 'blockquote_end') {
19721             body += this.tok();
19722           }
19723     
19724           return this.renderer.blockquote(body);
19725         }
19726         case 'list_start': {
19727           var body = ''
19728             , ordered = this.token.ordered;
19729     
19730           while (this.next().type !== 'list_end') {
19731             body += this.tok();
19732           }
19733     
19734           return this.renderer.list(body, ordered);
19735         }
19736         case 'list_item_start': {
19737           var body = '';
19738     
19739           while (this.next().type !== 'list_item_end') {
19740             body += this.token.type === 'text'
19741               ? this.parseText()
19742               : this.tok();
19743           }
19744     
19745           return this.renderer.listitem(body);
19746         }
19747         case 'loose_item_start': {
19748           var body = '';
19749     
19750           while (this.next().type !== 'list_item_end') {
19751             body += this.tok();
19752           }
19753     
19754           return this.renderer.listitem(body);
19755         }
19756         case 'html': {
19757           var html = !this.token.pre && !this.options.pedantic
19758             ? this.inline.output(this.token.text)
19759             : this.token.text;
19760           return this.renderer.html(html);
19761         }
19762         case 'paragraph': {
19763           return this.renderer.paragraph(this.inline.output(this.token.text));
19764         }
19765         case 'text': {
19766           return this.renderer.paragraph(this.parseText());
19767         }
19768       }
19769     };
19770   
19771     
19772     /**
19773      * Marked
19774      */
19775          /**
19776          * eval:var:marked
19777     */
19778     var marked = function (src, opt, callback) {
19779       if (callback || typeof opt === 'function') {
19780         if (!callback) {
19781           callback = opt;
19782           opt = null;
19783         }
19784     
19785         opt = merge({}, marked.defaults, opt || {});
19786     
19787         var highlight = opt.highlight
19788           , tokens
19789           , pending
19790           , i = 0;
19791     
19792         try {
19793           tokens = Lexer.lex(src, opt)
19794         } catch (e) {
19795           return callback(e);
19796         }
19797     
19798         pending = tokens.length;
19799          /**
19800          * eval:var:done
19801     */
19802         var done = function(err) {
19803           if (err) {
19804             opt.highlight = highlight;
19805             return callback(err);
19806           }
19807     
19808           var out;
19809     
19810           try {
19811             out = Parser.parse(tokens, opt);
19812           } catch (e) {
19813             err = e;
19814           }
19815     
19816           opt.highlight = highlight;
19817     
19818           return err
19819             ? callback(err)
19820             : callback(null, out);
19821         };
19822     
19823         if (!highlight || highlight.length < 3) {
19824           return done();
19825         }
19826     
19827         delete opt.highlight;
19828     
19829         if (!pending) { return done(); }
19830     
19831         for (; i < tokens.length; i++) {
19832           (function(token) {
19833             if (token.type !== 'code') {
19834               return --pending || done();
19835             }
19836             return highlight(token.text, token.lang, function(err, code) {
19837               if (err) { return done(err); }
19838               if (code == null || code === token.text) {
19839                 return --pending || done();
19840               }
19841               token.text = code;
19842               token.escaped = true;
19843               --pending || done();
19844             });
19845           })(tokens[i]);
19846         }
19847     
19848         return;
19849       }
19850       try {
19851         if (opt) { opt = merge({}, marked.defaults, opt); }
19852         return Parser.parse(Lexer.lex(src, opt), opt);
19853       } catch (e) {
19854         e.message += '\nPlease report this to https://github.com/chjj/marked.';
19855         if ((opt || marked.defaults).silent) {
19856           return '<p>An error occured:</p><pre>'
19857             + escape(e.message + '', true)
19858             + '</pre>';
19859         }
19860         throw e;
19861       }
19862     }
19863     
19864     /**
19865      * Options
19866      */
19867     
19868     marked.options =
19869     marked.setOptions = function(opt) {
19870       merge(marked.defaults, opt);
19871       return marked;
19872     };
19873     
19874     marked.defaults = {
19875       gfm: true,
19876       tables: true,
19877       breaks: false,
19878       pedantic: false,
19879       sanitize: false,
19880       sanitizer: null,
19881       mangle: true,
19882       smartLists: false,
19883       silent: false,
19884       highlight: null,
19885       langPrefix: 'lang-',
19886       smartypants: false,
19887       headerPrefix: '',
19888       renderer: new Renderer,
19889       xhtml: false
19890     };
19891     
19892     /**
19893      * Expose
19894      */
19895     
19896     marked.Parser = Parser;
19897     marked.parser = Parser.parse;
19898     
19899     marked.Renderer = Renderer;
19900     
19901     marked.Lexer = Lexer;
19902     marked.lexer = Lexer.lex;
19903     
19904     marked.InlineLexer = InlineLexer;
19905     marked.inlineLexer = InlineLexer.output;
19906     
19907     marked.parse = marked;
19908     
19909     Roo.Markdown.marked = marked;
19910
19911 })();/*
19912  * Based on:
19913  * Ext JS Library 1.1.1
19914  * Copyright(c) 2006-2007, Ext JS, LLC.
19915  *
19916  * Originally Released Under LGPL - original licence link has changed is not relivant.
19917  *
19918  * Fork - LGPL
19919  * <script type="text/javascript">
19920  */
19921
19922
19923
19924 /*
19925  * These classes are derivatives of the similarly named classes in the YUI Library.
19926  * The original license:
19927  * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
19928  * Code licensed under the BSD License:
19929  * http://developer.yahoo.net/yui/license.txt
19930  */
19931
19932 (function() {
19933
19934 var Event=Roo.EventManager;
19935 var Dom=Roo.lib.Dom;
19936
19937 /**
19938  * @class Roo.dd.DragDrop
19939  * @extends Roo.util.Observable
19940  * Defines the interface and base operation of items that that can be
19941  * dragged or can be drop targets.  It was designed to be extended, overriding
19942  * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
19943  * Up to three html elements can be associated with a DragDrop instance:
19944  * <ul>
19945  * <li>linked element: the element that is passed into the constructor.
19946  * This is the element which defines the boundaries for interaction with
19947  * other DragDrop objects.</li>
19948  * <li>handle element(s): The drag operation only occurs if the element that
19949  * was clicked matches a handle element.  By default this is the linked
19950  * element, but there are times that you will want only a portion of the
19951  * linked element to initiate the drag operation, and the setHandleElId()
19952  * method provides a way to define this.</li>
19953  * <li>drag element: this represents the element that would be moved along
19954  * with the cursor during a drag operation.  By default, this is the linked
19955  * element itself as in {@link Roo.dd.DD}.  setDragElId() lets you define
19956  * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
19957  * </li>
19958  * </ul>
19959  * This class should not be instantiated until the onload event to ensure that
19960  * the associated elements are available.
19961  * The following would define a DragDrop obj that would interact with any
19962  * other DragDrop obj in the "group1" group:
19963  * <pre>
19964  *  dd = new Roo.dd.DragDrop("div1", "group1");
19965  * </pre>
19966  * Since none of the event handlers have been implemented, nothing would
19967  * actually happen if you were to run the code above.  Normally you would
19968  * override this class or one of the default implementations, but you can
19969  * also override the methods you want on an instance of the class...
19970  * <pre>
19971  *  dd.onDragDrop = function(e, id) {
19972  *  &nbsp;&nbsp;alert("dd was dropped on " + id);
19973  *  }
19974  * </pre>
19975  * @constructor
19976  * @param {String} id of the element that is linked to this instance
19977  * @param {String} sGroup the group of related DragDrop objects
19978  * @param {object} config an object containing configurable attributes
19979  *                Valid properties for DragDrop:
19980  *                    padding, isTarget, maintainOffset, primaryButtonOnly
19981  */
19982 Roo.dd.DragDrop = function(id, sGroup, config) {
19983     if (id) {
19984         this.init(id, sGroup, config);
19985     }
19986     
19987 };
19988
19989 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
19990
19991     /**
19992      * The id of the element associated with this object.  This is what we
19993      * refer to as the "linked element" because the size and position of
19994      * this element is used to determine when the drag and drop objects have
19995      * interacted.
19996      * @property id
19997      * @type String
19998      */
19999     id: null,
20000
20001     /**
20002      * Configuration attributes passed into the constructor
20003      * @property config
20004      * @type object
20005      */
20006     config: null,
20007
20008     /**
20009      * The id of the element that will be dragged.  By default this is same
20010      * as the linked element , but could be changed to another element. Ex:
20011      * Roo.dd.DDProxy
20012      * @property dragElId
20013      * @type String
20014      * @private
20015      */
20016     dragElId: null,
20017
20018     /**
20019      * the id of the element that initiates the drag operation.  By default
20020      * this is the linked element, but could be changed to be a child of this
20021      * element.  This lets us do things like only starting the drag when the
20022      * header element within the linked html element is clicked.
20023      * @property handleElId
20024      * @type String
20025      * @private
20026      */
20027     handleElId: null,
20028
20029     /**
20030      * An associative array of HTML tags that will be ignored if clicked.
20031      * @property invalidHandleTypes
20032      * @type {string: string}
20033      */
20034     invalidHandleTypes: null,
20035
20036     /**
20037      * An associative array of ids for elements that will be ignored if clicked
20038      * @property invalidHandleIds
20039      * @type {string: string}
20040      */
20041     invalidHandleIds: null,
20042
20043     /**
20044      * An indexted array of css class names for elements that will be ignored
20045      * if clicked.
20046      * @property invalidHandleClasses
20047      * @type string[]
20048      */
20049     invalidHandleClasses: null,
20050
20051     /**
20052      * The linked element's absolute X position at the time the drag was
20053      * started
20054      * @property startPageX
20055      * @type int
20056      * @private
20057      */
20058     startPageX: 0,
20059
20060     /**
20061      * The linked element's absolute X position at the time the drag was
20062      * started
20063      * @property startPageY
20064      * @type int
20065      * @private
20066      */
20067     startPageY: 0,
20068
20069     /**
20070      * The group defines a logical collection of DragDrop objects that are
20071      * related.  Instances only get events when interacting with other
20072      * DragDrop object in the same group.  This lets us define multiple
20073      * groups using a single DragDrop subclass if we want.
20074      * @property groups
20075      * @type {string: string}
20076      */
20077     groups: null,
20078
20079     /**
20080      * Individual drag/drop instances can be locked.  This will prevent
20081      * onmousedown start drag.
20082      * @property locked
20083      * @type boolean
20084      * @private
20085      */
20086     locked: false,
20087
20088     /**
20089      * Lock this instance
20090      * @method lock
20091      */
20092     lock: function() { this.locked = true; },
20093
20094     /**
20095      * Unlock this instace
20096      * @method unlock
20097      */
20098     unlock: function() { this.locked = false; },
20099
20100     /**
20101      * By default, all insances can be a drop target.  This can be disabled by
20102      * setting isTarget to false.
20103      * @method isTarget
20104      * @type boolean
20105      */
20106     isTarget: true,
20107
20108     /**
20109      * The padding configured for this drag and drop object for calculating
20110      * the drop zone intersection with this object.
20111      * @method padding
20112      * @type int[]
20113      */
20114     padding: null,
20115
20116     /**
20117      * Cached reference to the linked element
20118      * @property _domRef
20119      * @private
20120      */
20121     _domRef: null,
20122
20123     /**
20124      * Internal typeof flag
20125      * @property __ygDragDrop
20126      * @private
20127      */
20128     __ygDragDrop: true,
20129
20130     /**
20131      * Set to true when horizontal contraints are applied
20132      * @property constrainX
20133      * @type boolean
20134      * @private
20135      */
20136     constrainX: false,
20137
20138     /**
20139      * Set to true when vertical contraints are applied
20140      * @property constrainY
20141      * @type boolean
20142      * @private
20143      */
20144     constrainY: false,
20145
20146     /**
20147      * The left constraint
20148      * @property minX
20149      * @type int
20150      * @private
20151      */
20152     minX: 0,
20153
20154     /**
20155      * The right constraint
20156      * @property maxX
20157      * @type int
20158      * @private
20159      */
20160     maxX: 0,
20161
20162     /**
20163      * The up constraint
20164      * @property minY
20165      * @type int
20166      * @type int
20167      * @private
20168      */
20169     minY: 0,
20170
20171     /**
20172      * The down constraint
20173      * @property maxY
20174      * @type int
20175      * @private
20176      */
20177     maxY: 0,
20178
20179     /**
20180      * Maintain offsets when we resetconstraints.  Set to true when you want
20181      * the position of the element relative to its parent to stay the same
20182      * when the page changes
20183      *
20184      * @property maintainOffset
20185      * @type boolean
20186      */
20187     maintainOffset: false,
20188
20189     /**
20190      * Array of pixel locations the element will snap to if we specified a
20191      * horizontal graduation/interval.  This array is generated automatically
20192      * when you define a tick interval.
20193      * @property xTicks
20194      * @type int[]
20195      */
20196     xTicks: null,
20197
20198     /**
20199      * Array of pixel locations the element will snap to if we specified a
20200      * vertical graduation/interval.  This array is generated automatically
20201      * when you define a tick interval.
20202      * @property yTicks
20203      * @type int[]
20204      */
20205     yTicks: null,
20206
20207     /**
20208      * By default the drag and drop instance will only respond to the primary
20209      * button click (left button for a right-handed mouse).  Set to true to
20210      * allow drag and drop to start with any mouse click that is propogated
20211      * by the browser
20212      * @property primaryButtonOnly
20213      * @type boolean
20214      */
20215     primaryButtonOnly: true,
20216
20217     /**
20218      * The availabe property is false until the linked dom element is accessible.
20219      * @property available
20220      * @type boolean
20221      */
20222     available: false,
20223
20224     /**
20225      * By default, drags can only be initiated if the mousedown occurs in the
20226      * region the linked element is.  This is done in part to work around a
20227      * bug in some browsers that mis-report the mousedown if the previous
20228      * mouseup happened outside of the window.  This property is set to true
20229      * if outer handles are defined.
20230      *
20231      * @property hasOuterHandles
20232      * @type boolean
20233      * @default false
20234      */
20235     hasOuterHandles: false,
20236
20237     /**
20238      * Code that executes immediately before the startDrag event
20239      * @method b4StartDrag
20240      * @private
20241      */
20242     b4StartDrag: function(x, y) { },
20243
20244     /**
20245      * Abstract method called after a drag/drop object is clicked
20246      * and the drag or mousedown time thresholds have beeen met.
20247      * @method startDrag
20248      * @param {int} X click location
20249      * @param {int} Y click location
20250      */
20251     startDrag: function(x, y) { /* override this */ },
20252
20253     /**
20254      * Code that executes immediately before the onDrag event
20255      * @method b4Drag
20256      * @private
20257      */
20258     b4Drag: function(e) { },
20259
20260     /**
20261      * Abstract method called during the onMouseMove event while dragging an
20262      * object.
20263      * @method onDrag
20264      * @param {Event} e the mousemove event
20265      */
20266     onDrag: function(e) { /* override this */ },
20267
20268     /**
20269      * Abstract method called when this element fist begins hovering over
20270      * another DragDrop obj
20271      * @method onDragEnter
20272      * @param {Event} e the mousemove event
20273      * @param {String|DragDrop[]} id In POINT mode, the element
20274      * id this is hovering over.  In INTERSECT mode, an array of one or more
20275      * dragdrop items being hovered over.
20276      */
20277     onDragEnter: function(e, id) { /* override this */ },
20278
20279     /**
20280      * Code that executes immediately before the onDragOver event
20281      * @method b4DragOver
20282      * @private
20283      */
20284     b4DragOver: function(e) { },
20285
20286     /**
20287      * Abstract method called when this element is hovering over another
20288      * DragDrop obj
20289      * @method onDragOver
20290      * @param {Event} e the mousemove event
20291      * @param {String|DragDrop[]} id In POINT mode, the element
20292      * id this is hovering over.  In INTERSECT mode, an array of dd items
20293      * being hovered over.
20294      */
20295     onDragOver: function(e, id) { /* override this */ },
20296
20297     /**
20298      * Code that executes immediately before the onDragOut event
20299      * @method b4DragOut
20300      * @private
20301      */
20302     b4DragOut: function(e) { },
20303
20304     /**
20305      * Abstract method called when we are no longer hovering over an element
20306      * @method onDragOut
20307      * @param {Event} e the mousemove event
20308      * @param {String|DragDrop[]} id In POINT mode, the element
20309      * id this was hovering over.  In INTERSECT mode, an array of dd items
20310      * that the mouse is no longer over.
20311      */
20312     onDragOut: function(e, id) { /* override this */ },
20313
20314     /**
20315      * Code that executes immediately before the onDragDrop event
20316      * @method b4DragDrop
20317      * @private
20318      */
20319     b4DragDrop: function(e) { },
20320
20321     /**
20322      * Abstract method called when this item is dropped on another DragDrop
20323      * obj
20324      * @method onDragDrop
20325      * @param {Event} e the mouseup event
20326      * @param {String|DragDrop[]} id In POINT mode, the element
20327      * id this was dropped on.  In INTERSECT mode, an array of dd items this
20328      * was dropped on.
20329      */
20330     onDragDrop: function(e, id) { /* override this */ },
20331
20332     /**
20333      * Abstract method called when this item is dropped on an area with no
20334      * drop target
20335      * @method onInvalidDrop
20336      * @param {Event} e the mouseup event
20337      */
20338     onInvalidDrop: function(e) { /* override this */ },
20339
20340     /**
20341      * Code that executes immediately before the endDrag event
20342      * @method b4EndDrag
20343      * @private
20344      */
20345     b4EndDrag: function(e) { },
20346
20347     /**
20348      * Fired when we are done dragging the object
20349      * @method endDrag
20350      * @param {Event} e the mouseup event
20351      */
20352     endDrag: function(e) { /* override this */ },
20353
20354     /**
20355      * Code executed immediately before the onMouseDown event
20356      * @method b4MouseDown
20357      * @param {Event} e the mousedown event
20358      * @private
20359      */
20360     b4MouseDown: function(e) {  },
20361
20362     /**
20363      * Event handler that fires when a drag/drop obj gets a mousedown
20364      * @method onMouseDown
20365      * @param {Event} e the mousedown event
20366      */
20367     onMouseDown: function(e) { /* override this */ },
20368
20369     /**
20370      * Event handler that fires when a drag/drop obj gets a mouseup
20371      * @method onMouseUp
20372      * @param {Event} e the mouseup event
20373      */
20374     onMouseUp: function(e) { /* override this */ },
20375
20376     /**
20377      * Override the onAvailable method to do what is needed after the initial
20378      * position was determined.
20379      * @method onAvailable
20380      */
20381     onAvailable: function () {
20382     },
20383
20384     /*
20385      * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
20386      * @type Object
20387      */
20388     defaultPadding : {left:0, right:0, top:0, bottom:0},
20389
20390     /*
20391      * Initializes the drag drop object's constraints to restrict movement to a certain element.
20392  *
20393  * Usage:
20394  <pre><code>
20395  var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
20396                 { dragElId: "existingProxyDiv" });
20397  dd.startDrag = function(){
20398      this.constrainTo("parent-id");
20399  };
20400  </code></pre>
20401  * Or you can initalize it using the {@link Roo.Element} object:
20402  <pre><code>
20403  Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
20404      startDrag : function(){
20405          this.constrainTo("parent-id");
20406      }
20407  });
20408  </code></pre>
20409      * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
20410      * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
20411      * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
20412      * an object containing the sides to pad. For example: {right:10, bottom:10}
20413      * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
20414      */
20415     constrainTo : function(constrainTo, pad, inContent){
20416         if(typeof pad == "number"){
20417             pad = {left: pad, right:pad, top:pad, bottom:pad};
20418         }
20419         pad = pad || this.defaultPadding;
20420         var b = Roo.get(this.getEl()).getBox();
20421         var ce = Roo.get(constrainTo);
20422         var s = ce.getScroll();
20423         var c, cd = ce.dom;
20424         if(cd == document.body){
20425             c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
20426         }else{
20427             xy = ce.getXY();
20428             c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
20429         }
20430
20431
20432         var topSpace = b.y - c.y;
20433         var leftSpace = b.x - c.x;
20434
20435         this.resetConstraints();
20436         this.setXConstraint(leftSpace - (pad.left||0), // left
20437                 c.width - leftSpace - b.width - (pad.right||0) //right
20438         );
20439         this.setYConstraint(topSpace - (pad.top||0), //top
20440                 c.height - topSpace - b.height - (pad.bottom||0) //bottom
20441         );
20442     },
20443
20444     /**
20445      * Returns a reference to the linked element
20446      * @method getEl
20447      * @return {HTMLElement} the html element
20448      */
20449     getEl: function() {
20450         if (!this._domRef) {
20451             this._domRef = Roo.getDom(this.id);
20452         }
20453
20454         return this._domRef;
20455     },
20456
20457     /**
20458      * Returns a reference to the actual element to drag.  By default this is
20459      * the same as the html element, but it can be assigned to another
20460      * element. An example of this can be found in Roo.dd.DDProxy
20461      * @method getDragEl
20462      * @return {HTMLElement} the html element
20463      */
20464     getDragEl: function() {
20465         return Roo.getDom(this.dragElId);
20466     },
20467
20468     /**
20469      * Sets up the DragDrop object.  Must be called in the constructor of any
20470      * Roo.dd.DragDrop subclass
20471      * @method init
20472      * @param id the id of the linked element
20473      * @param {String} sGroup the group of related items
20474      * @param {object} config configuration attributes
20475      */
20476     init: function(id, sGroup, config) {
20477         this.initTarget(id, sGroup, config);
20478         if (!Roo.isTouch) {
20479             Event.on(this.id, "mousedown", this.handleMouseDown, this);
20480         }
20481         Event.on(this.id, "touchstart", this.handleMouseDown, this);
20482         // Event.on(this.id, "selectstart", Event.preventDefault);
20483     },
20484
20485     /**
20486      * Initializes Targeting functionality only... the object does not
20487      * get a mousedown handler.
20488      * @method initTarget
20489      * @param id the id of the linked element
20490      * @param {String} sGroup the group of related items
20491      * @param {object} config configuration attributes
20492      */
20493     initTarget: function(id, sGroup, config) {
20494
20495         // configuration attributes
20496         this.config = config || {};
20497
20498         // create a local reference to the drag and drop manager
20499         this.DDM = Roo.dd.DDM;
20500         // initialize the groups array
20501         this.groups = {};
20502
20503         // assume that we have an element reference instead of an id if the
20504         // parameter is not a string
20505         if (typeof id !== "string") {
20506             id = Roo.id(id);
20507         }
20508
20509         // set the id
20510         this.id = id;
20511
20512         // add to an interaction group
20513         this.addToGroup((sGroup) ? sGroup : "default");
20514
20515         // We don't want to register this as the handle with the manager
20516         // so we just set the id rather than calling the setter.
20517         this.handleElId = id;
20518
20519         // the linked element is the element that gets dragged by default
20520         this.setDragElId(id);
20521
20522         // by default, clicked anchors will not start drag operations.
20523         this.invalidHandleTypes = { A: "A" };
20524         this.invalidHandleIds = {};
20525         this.invalidHandleClasses = [];
20526
20527         this.applyConfig();
20528
20529         this.handleOnAvailable();
20530     },
20531
20532     /**
20533      * Applies the configuration parameters that were passed into the constructor.
20534      * This is supposed to happen at each level through the inheritance chain.  So
20535      * a DDProxy implentation will execute apply config on DDProxy, DD, and
20536      * DragDrop in order to get all of the parameters that are available in
20537      * each object.
20538      * @method applyConfig
20539      */
20540     applyConfig: function() {
20541
20542         // configurable properties:
20543         //    padding, isTarget, maintainOffset, primaryButtonOnly
20544         this.padding           = this.config.padding || [0, 0, 0, 0];
20545         this.isTarget          = (this.config.isTarget !== false);
20546         this.maintainOffset    = (this.config.maintainOffset);
20547         this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
20548
20549     },
20550
20551     /**
20552      * Executed when the linked element is available
20553      * @method handleOnAvailable
20554      * @private
20555      */
20556     handleOnAvailable: function() {
20557         this.available = true;
20558         this.resetConstraints();
20559         this.onAvailable();
20560     },
20561
20562      /**
20563      * Configures the padding for the target zone in px.  Effectively expands
20564      * (or reduces) the virtual object size for targeting calculations.
20565      * Supports css-style shorthand; if only one parameter is passed, all sides
20566      * will have that padding, and if only two are passed, the top and bottom
20567      * will have the first param, the left and right the second.
20568      * @method setPadding
20569      * @param {int} iTop    Top pad
20570      * @param {int} iRight  Right pad
20571      * @param {int} iBot    Bot pad
20572      * @param {int} iLeft   Left pad
20573      */
20574     setPadding: function(iTop, iRight, iBot, iLeft) {
20575         // this.padding = [iLeft, iRight, iTop, iBot];
20576         if (!iRight && 0 !== iRight) {
20577             this.padding = [iTop, iTop, iTop, iTop];
20578         } else if (!iBot && 0 !== iBot) {
20579             this.padding = [iTop, iRight, iTop, iRight];
20580         } else {
20581             this.padding = [iTop, iRight, iBot, iLeft];
20582         }
20583     },
20584
20585     /**
20586      * Stores the initial placement of the linked element.
20587      * @method setInitialPosition
20588      * @param {int} diffX   the X offset, default 0
20589      * @param {int} diffY   the Y offset, default 0
20590      */
20591     setInitPosition: function(diffX, diffY) {
20592         var el = this.getEl();
20593
20594         if (!this.DDM.verifyEl(el)) {
20595             return;
20596         }
20597
20598         var dx = diffX || 0;
20599         var dy = diffY || 0;
20600
20601         var p = Dom.getXY( el );
20602
20603         this.initPageX = p[0] - dx;
20604         this.initPageY = p[1] - dy;
20605
20606         this.lastPageX = p[0];
20607         this.lastPageY = p[1];
20608
20609
20610         this.setStartPosition(p);
20611     },
20612
20613     /**
20614      * Sets the start position of the element.  This is set when the obj
20615      * is initialized, the reset when a drag is started.
20616      * @method setStartPosition
20617      * @param pos current position (from previous lookup)
20618      * @private
20619      */
20620     setStartPosition: function(pos) {
20621         var p = pos || Dom.getXY( this.getEl() );
20622         this.deltaSetXY = null;
20623
20624         this.startPageX = p[0];
20625         this.startPageY = p[1];
20626     },
20627
20628     /**
20629      * Add this instance to a group of related drag/drop objects.  All
20630      * instances belong to at least one group, and can belong to as many
20631      * groups as needed.
20632      * @method addToGroup
20633      * @param sGroup {string} the name of the group
20634      */
20635     addToGroup: function(sGroup) {
20636         this.groups[sGroup] = true;
20637         this.DDM.regDragDrop(this, sGroup);
20638     },
20639
20640     /**
20641      * Remove's this instance from the supplied interaction group
20642      * @method removeFromGroup
20643      * @param {string}  sGroup  The group to drop
20644      */
20645     removeFromGroup: function(sGroup) {
20646         if (this.groups[sGroup]) {
20647             delete this.groups[sGroup];
20648         }
20649
20650         this.DDM.removeDDFromGroup(this, sGroup);
20651     },
20652
20653     /**
20654      * Allows you to specify that an element other than the linked element
20655      * will be moved with the cursor during a drag
20656      * @method setDragElId
20657      * @param id {string} the id of the element that will be used to initiate the drag
20658      */
20659     setDragElId: function(id) {
20660         this.dragElId = id;
20661     },
20662
20663     /**
20664      * Allows you to specify a child of the linked element that should be
20665      * used to initiate the drag operation.  An example of this would be if
20666      * you have a content div with text and links.  Clicking anywhere in the
20667      * content area would normally start the drag operation.  Use this method
20668      * to specify that an element inside of the content div is the element
20669      * that starts the drag operation.
20670      * @method setHandleElId
20671      * @param id {string} the id of the element that will be used to
20672      * initiate the drag.
20673      */
20674     setHandleElId: function(id) {
20675         if (typeof id !== "string") {
20676             id = Roo.id(id);
20677         }
20678         this.handleElId = id;
20679         this.DDM.regHandle(this.id, id);
20680     },
20681
20682     /**
20683      * Allows you to set an element outside of the linked element as a drag
20684      * handle
20685      * @method setOuterHandleElId
20686      * @param id the id of the element that will be used to initiate the drag
20687      */
20688     setOuterHandleElId: function(id) {
20689         if (typeof id !== "string") {
20690             id = Roo.id(id);
20691         }
20692         Event.on(id, "mousedown",
20693                 this.handleMouseDown, this);
20694         this.setHandleElId(id);
20695
20696         this.hasOuterHandles = true;
20697     },
20698
20699     /**
20700      * Remove all drag and drop hooks for this element
20701      * @method unreg
20702      */
20703     unreg: function() {
20704         Event.un(this.id, "mousedown",
20705                 this.handleMouseDown);
20706         Event.un(this.id, "touchstart",
20707                 this.handleMouseDown);
20708         this._domRef = null;
20709         this.DDM._remove(this);
20710     },
20711
20712     destroy : function(){
20713         this.unreg();
20714     },
20715
20716     /**
20717      * Returns true if this instance is locked, or the drag drop mgr is locked
20718      * (meaning that all drag/drop is disabled on the page.)
20719      * @method isLocked
20720      * @return {boolean} true if this obj or all drag/drop is locked, else
20721      * false
20722      */
20723     isLocked: function() {
20724         return (this.DDM.isLocked() || this.locked);
20725     },
20726
20727     /**
20728      * Fired when this object is clicked
20729      * @method handleMouseDown
20730      * @param {Event} e
20731      * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
20732      * @private
20733      */
20734     handleMouseDown: function(e, oDD){
20735      
20736         if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
20737             //Roo.log('not touch/ button !=0');
20738             return;
20739         }
20740         if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
20741             return; // double touch..
20742         }
20743         
20744
20745         if (this.isLocked()) {
20746             //Roo.log('locked');
20747             return;
20748         }
20749
20750         this.DDM.refreshCache(this.groups);
20751 //        Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
20752         var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
20753         if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) )  {
20754             //Roo.log('no outer handes or not over target');
20755                 // do nothing.
20756         } else {
20757 //            Roo.log('check validator');
20758             if (this.clickValidator(e)) {
20759 //                Roo.log('validate success');
20760                 // set the initial element position
20761                 this.setStartPosition();
20762
20763
20764                 this.b4MouseDown(e);
20765                 this.onMouseDown(e);
20766
20767                 this.DDM.handleMouseDown(e, this);
20768
20769                 this.DDM.stopEvent(e);
20770             } else {
20771
20772
20773             }
20774         }
20775     },
20776
20777     clickValidator: function(e) {
20778         var target = e.getTarget();
20779         return ( this.isValidHandleChild(target) &&
20780                     (this.id == this.handleElId ||
20781                         this.DDM.handleWasClicked(target, this.id)) );
20782     },
20783
20784     /**
20785      * Allows you to specify a tag name that should not start a drag operation
20786      * when clicked.  This is designed to facilitate embedding links within a
20787      * drag handle that do something other than start the drag.
20788      * @method addInvalidHandleType
20789      * @param {string} tagName the type of element to exclude
20790      */
20791     addInvalidHandleType: function(tagName) {
20792         var type = tagName.toUpperCase();
20793         this.invalidHandleTypes[type] = type;
20794     },
20795
20796     /**
20797      * Lets you to specify an element id for a child of a drag handle
20798      * that should not initiate a drag
20799      * @method addInvalidHandleId
20800      * @param {string} id the element id of the element you wish to ignore
20801      */
20802     addInvalidHandleId: function(id) {
20803         if (typeof id !== "string") {
20804             id = Roo.id(id);
20805         }
20806         this.invalidHandleIds[id] = id;
20807     },
20808
20809     /**
20810      * Lets you specify a css class of elements that will not initiate a drag
20811      * @method addInvalidHandleClass
20812      * @param {string} cssClass the class of the elements you wish to ignore
20813      */
20814     addInvalidHandleClass: function(cssClass) {
20815         this.invalidHandleClasses.push(cssClass);
20816     },
20817
20818     /**
20819      * Unsets an excluded tag name set by addInvalidHandleType
20820      * @method removeInvalidHandleType
20821      * @param {string} tagName the type of element to unexclude
20822      */
20823     removeInvalidHandleType: function(tagName) {
20824         var type = tagName.toUpperCase();
20825         // this.invalidHandleTypes[type] = null;
20826         delete this.invalidHandleTypes[type];
20827     },
20828
20829     /**
20830      * Unsets an invalid handle id
20831      * @method removeInvalidHandleId
20832      * @param {string} id the id of the element to re-enable
20833      */
20834     removeInvalidHandleId: function(id) {
20835         if (typeof id !== "string") {
20836             id = Roo.id(id);
20837         }
20838         delete this.invalidHandleIds[id];
20839     },
20840
20841     /**
20842      * Unsets an invalid css class
20843      * @method removeInvalidHandleClass
20844      * @param {string} cssClass the class of the element(s) you wish to
20845      * re-enable
20846      */
20847     removeInvalidHandleClass: function(cssClass) {
20848         for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
20849             if (this.invalidHandleClasses[i] == cssClass) {
20850                 delete this.invalidHandleClasses[i];
20851             }
20852         }
20853     },
20854
20855     /**
20856      * Checks the tag exclusion list to see if this click should be ignored
20857      * @method isValidHandleChild
20858      * @param {HTMLElement} node the HTMLElement to evaluate
20859      * @return {boolean} true if this is a valid tag type, false if not
20860      */
20861     isValidHandleChild: function(node) {
20862
20863         var valid = true;
20864         // var n = (node.nodeName == "#text") ? node.parentNode : node;
20865         var nodeName;
20866         try {
20867             nodeName = node.nodeName.toUpperCase();
20868         } catch(e) {
20869             nodeName = node.nodeName;
20870         }
20871         valid = valid && !this.invalidHandleTypes[nodeName];
20872         valid = valid && !this.invalidHandleIds[node.id];
20873
20874         for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
20875             valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
20876         }
20877
20878
20879         return valid;
20880
20881     },
20882
20883     /**
20884      * Create the array of horizontal tick marks if an interval was specified
20885      * in setXConstraint().
20886      * @method setXTicks
20887      * @private
20888      */
20889     setXTicks: function(iStartX, iTickSize) {
20890         this.xTicks = [];
20891         this.xTickSize = iTickSize;
20892
20893         var tickMap = {};
20894
20895         for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
20896             if (!tickMap[i]) {
20897                 this.xTicks[this.xTicks.length] = i;
20898                 tickMap[i] = true;
20899             }
20900         }
20901
20902         for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
20903             if (!tickMap[i]) {
20904                 this.xTicks[this.xTicks.length] = i;
20905                 tickMap[i] = true;
20906             }
20907         }
20908
20909         this.xTicks.sort(this.DDM.numericSort) ;
20910     },
20911
20912     /**
20913      * Create the array of vertical tick marks if an interval was specified in
20914      * setYConstraint().
20915      * @method setYTicks
20916      * @private
20917      */
20918     setYTicks: function(iStartY, iTickSize) {
20919         this.yTicks = [];
20920         this.yTickSize = iTickSize;
20921
20922         var tickMap = {};
20923
20924         for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
20925             if (!tickMap[i]) {
20926                 this.yTicks[this.yTicks.length] = i;
20927                 tickMap[i] = true;
20928             }
20929         }
20930
20931         for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
20932             if (!tickMap[i]) {
20933                 this.yTicks[this.yTicks.length] = i;
20934                 tickMap[i] = true;
20935             }
20936         }
20937
20938         this.yTicks.sort(this.DDM.numericSort) ;
20939     },
20940
20941     /**
20942      * By default, the element can be dragged any place on the screen.  Use
20943      * this method to limit the horizontal travel of the element.  Pass in
20944      * 0,0 for the parameters if you want to lock the drag to the y axis.
20945      * @method setXConstraint
20946      * @param {int} iLeft the number of pixels the element can move to the left
20947      * @param {int} iRight the number of pixels the element can move to the
20948      * right
20949      * @param {int} iTickSize optional parameter for specifying that the
20950      * element
20951      * should move iTickSize pixels at a time.
20952      */
20953     setXConstraint: function(iLeft, iRight, iTickSize) {
20954         this.leftConstraint = iLeft;
20955         this.rightConstraint = iRight;
20956
20957         this.minX = this.initPageX - iLeft;
20958         this.maxX = this.initPageX + iRight;
20959         if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
20960
20961         this.constrainX = true;
20962     },
20963
20964     /**
20965      * Clears any constraints applied to this instance.  Also clears ticks
20966      * since they can't exist independent of a constraint at this time.
20967      * @method clearConstraints
20968      */
20969     clearConstraints: function() {
20970         this.constrainX = false;
20971         this.constrainY = false;
20972         this.clearTicks();
20973     },
20974
20975     /**
20976      * Clears any tick interval defined for this instance
20977      * @method clearTicks
20978      */
20979     clearTicks: function() {
20980         this.xTicks = null;
20981         this.yTicks = null;
20982         this.xTickSize = 0;
20983         this.yTickSize = 0;
20984     },
20985
20986     /**
20987      * By default, the element can be dragged any place on the screen.  Set
20988      * this to limit the vertical travel of the element.  Pass in 0,0 for the
20989      * parameters if you want to lock the drag to the x axis.
20990      * @method setYConstraint
20991      * @param {int} iUp the number of pixels the element can move up
20992      * @param {int} iDown the number of pixels the element can move down
20993      * @param {int} iTickSize optional parameter for specifying that the
20994      * element should move iTickSize pixels at a time.
20995      */
20996     setYConstraint: function(iUp, iDown, iTickSize) {
20997         this.topConstraint = iUp;
20998         this.bottomConstraint = iDown;
20999
21000         this.minY = this.initPageY - iUp;
21001         this.maxY = this.initPageY + iDown;
21002         if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
21003
21004         this.constrainY = true;
21005
21006     },
21007
21008     /**
21009      * resetConstraints must be called if you manually reposition a dd element.
21010      * @method resetConstraints
21011      * @param {boolean} maintainOffset
21012      */
21013     resetConstraints: function() {
21014
21015
21016         // Maintain offsets if necessary
21017         if (this.initPageX || this.initPageX === 0) {
21018             // figure out how much this thing has moved
21019             var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
21020             var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
21021
21022             this.setInitPosition(dx, dy);
21023
21024         // This is the first time we have detected the element's position
21025         } else {
21026             this.setInitPosition();
21027         }
21028
21029         if (this.constrainX) {
21030             this.setXConstraint( this.leftConstraint,
21031                                  this.rightConstraint,
21032                                  this.xTickSize        );
21033         }
21034
21035         if (this.constrainY) {
21036             this.setYConstraint( this.topConstraint,
21037                                  this.bottomConstraint,
21038                                  this.yTickSize         );
21039         }
21040     },
21041
21042     /**
21043      * Normally the drag element is moved pixel by pixel, but we can specify
21044      * that it move a number of pixels at a time.  This method resolves the
21045      * location when we have it set up like this.
21046      * @method getTick
21047      * @param {int} val where we want to place the object
21048      * @param {int[]} tickArray sorted array of valid points
21049      * @return {int} the closest tick
21050      * @private
21051      */
21052     getTick: function(val, tickArray) {
21053
21054         if (!tickArray) {
21055             // If tick interval is not defined, it is effectively 1 pixel,
21056             // so we return the value passed to us.
21057             return val;
21058         } else if (tickArray[0] >= val) {
21059             // The value is lower than the first tick, so we return the first
21060             // tick.
21061             return tickArray[0];
21062         } else {
21063             for (var i=0, len=tickArray.length; i<len; ++i) {
21064                 var next = i + 1;
21065                 if (tickArray[next] && tickArray[next] >= val) {
21066                     var diff1 = val - tickArray[i];
21067                     var diff2 = tickArray[next] - val;
21068                     return (diff2 > diff1) ? tickArray[i] : tickArray[next];
21069                 }
21070             }
21071
21072             // The value is larger than the last tick, so we return the last
21073             // tick.
21074             return tickArray[tickArray.length - 1];
21075         }
21076     },
21077
21078     /**
21079      * toString method
21080      * @method toString
21081      * @return {string} string representation of the dd obj
21082      */
21083     toString: function() {
21084         return ("DragDrop " + this.id);
21085     }
21086
21087 });
21088
21089 })();
21090 /*
21091  * Based on:
21092  * Ext JS Library 1.1.1
21093  * Copyright(c) 2006-2007, Ext JS, LLC.
21094  *
21095  * Originally Released Under LGPL - original licence link has changed is not relivant.
21096  *
21097  * Fork - LGPL
21098  * <script type="text/javascript">
21099  */
21100
21101
21102 /**
21103  * The drag and drop utility provides a framework for building drag and drop
21104  * applications.  In addition to enabling drag and drop for specific elements,
21105  * the drag and drop elements are tracked by the manager class, and the
21106  * interactions between the various elements are tracked during the drag and
21107  * the implementing code is notified about these important moments.
21108  */
21109
21110 // Only load the library once.  Rewriting the manager class would orphan
21111 // existing drag and drop instances.
21112 if (!Roo.dd.DragDropMgr) {
21113
21114 /**
21115  * @class Roo.dd.DragDropMgr
21116  * DragDropMgr is a singleton that tracks the element interaction for
21117  * all DragDrop items in the window.  Generally, you will not call
21118  * this class directly, but it does have helper methods that could
21119  * be useful in your DragDrop implementations.
21120  * @static
21121  */
21122 Roo.dd.DragDropMgr = function() {
21123
21124     var Event = Roo.EventManager;
21125
21126     return {
21127
21128         /**
21129          * Two dimensional Array of registered DragDrop objects.  The first
21130          * dimension is the DragDrop item group, the second the DragDrop
21131          * object.
21132          * @property ids
21133          * @type {string: string}
21134          * @private
21135          * @static
21136          */
21137         ids: {},
21138
21139         /**
21140          * Array of element ids defined as drag handles.  Used to determine
21141          * if the element that generated the mousedown event is actually the
21142          * handle and not the html element itself.
21143          * @property handleIds
21144          * @type {string: string}
21145          * @private
21146          * @static
21147          */
21148         handleIds: {},
21149
21150         /**
21151          * the DragDrop object that is currently being dragged
21152          * @property dragCurrent
21153          * @type DragDrop
21154          * @private
21155          * @static
21156          **/
21157         dragCurrent: null,
21158
21159         /**
21160          * the DragDrop object(s) that are being hovered over
21161          * @property dragOvers
21162          * @type Array
21163          * @private
21164          * @static
21165          */
21166         dragOvers: {},
21167
21168         /**
21169          * the X distance between the cursor and the object being dragged
21170          * @property deltaX
21171          * @type int
21172          * @private
21173          * @static
21174          */
21175         deltaX: 0,
21176
21177         /**
21178          * the Y distance between the cursor and the object being dragged
21179          * @property deltaY
21180          * @type int
21181          * @private
21182          * @static
21183          */
21184         deltaY: 0,
21185
21186         /**
21187          * Flag to determine if we should prevent the default behavior of the
21188          * events we define. By default this is true, but this can be set to
21189          * false if you need the default behavior (not recommended)
21190          * @property preventDefault
21191          * @type boolean
21192          * @static
21193          */
21194         preventDefault: true,
21195
21196         /**
21197          * Flag to determine if we should stop the propagation of the events
21198          * we generate. This is true by default but you may want to set it to
21199          * false if the html element contains other features that require the
21200          * mouse click.
21201          * @property stopPropagation
21202          * @type boolean
21203          * @static
21204          */
21205         stopPropagation: true,
21206
21207         /**
21208          * Internal flag that is set to true when drag and drop has been
21209          * intialized
21210          * @property initialized
21211          * @private
21212          * @static
21213          */
21214         initalized: false,
21215
21216         /**
21217          * All drag and drop can be disabled.
21218          * @property locked
21219          * @private
21220          * @static
21221          */
21222         locked: false,
21223
21224         /**
21225          * Called the first time an element is registered.
21226          * @method init
21227          * @private
21228          * @static
21229          */
21230         init: function() {
21231             this.initialized = true;
21232         },
21233
21234         /**
21235          * In point mode, drag and drop interaction is defined by the
21236          * location of the cursor during the drag/drop
21237          * @property POINT
21238          * @type int
21239          * @static
21240          */
21241         POINT: 0,
21242
21243         /**
21244          * In intersect mode, drag and drop interactio nis defined by the
21245          * overlap of two or more drag and drop objects.
21246          * @property INTERSECT
21247          * @type int
21248          * @static
21249          */
21250         INTERSECT: 1,
21251
21252         /**
21253          * The current drag and drop mode.  Default: POINT
21254          * @property mode
21255          * @type int
21256          * @static
21257          */
21258         mode: 0,
21259
21260         /**
21261          * Runs method on all drag and drop objects
21262          * @method _execOnAll
21263          * @private
21264          * @static
21265          */
21266         _execOnAll: function(sMethod, args) {
21267             for (var i in this.ids) {
21268                 for (var j in this.ids[i]) {
21269                     var oDD = this.ids[i][j];
21270                     if (! this.isTypeOfDD(oDD)) {
21271                         continue;
21272                     }
21273                     oDD[sMethod].apply(oDD, args);
21274                 }
21275             }
21276         },
21277
21278         /**
21279          * Drag and drop initialization.  Sets up the global event handlers
21280          * @method _onLoad
21281          * @private
21282          * @static
21283          */
21284         _onLoad: function() {
21285
21286             this.init();
21287
21288             if (!Roo.isTouch) {
21289                 Event.on(document, "mouseup",   this.handleMouseUp, this, true);
21290                 Event.on(document, "mousemove", this.handleMouseMove, this, true);
21291             }
21292             Event.on(document, "touchend",   this.handleMouseUp, this, true);
21293             Event.on(document, "touchmove", this.handleMouseMove, this, true);
21294             
21295             Event.on(window,   "unload",    this._onUnload, this, true);
21296             Event.on(window,   "resize",    this._onResize, this, true);
21297             // Event.on(window,   "mouseout",    this._test);
21298
21299         },
21300
21301         /**
21302          * Reset constraints on all drag and drop objs
21303          * @method _onResize
21304          * @private
21305          * @static
21306          */
21307         _onResize: function(e) {
21308             this._execOnAll("resetConstraints", []);
21309         },
21310
21311         /**
21312          * Lock all drag and drop functionality
21313          * @method lock
21314          * @static
21315          */
21316         lock: function() { this.locked = true; },
21317
21318         /**
21319          * Unlock all drag and drop functionality
21320          * @method unlock
21321          * @static
21322          */
21323         unlock: function() { this.locked = false; },
21324
21325         /**
21326          * Is drag and drop locked?
21327          * @method isLocked
21328          * @return {boolean} True if drag and drop is locked, false otherwise.
21329          * @static
21330          */
21331         isLocked: function() { return this.locked; },
21332
21333         /**
21334          * Location cache that is set for all drag drop objects when a drag is
21335          * initiated, cleared when the drag is finished.
21336          * @property locationCache
21337          * @private
21338          * @static
21339          */
21340         locationCache: {},
21341
21342         /**
21343          * Set useCache to false if you want to force object the lookup of each
21344          * drag and drop linked element constantly during a drag.
21345          * @property useCache
21346          * @type boolean
21347          * @static
21348          */
21349         useCache: true,
21350
21351         /**
21352          * The number of pixels that the mouse needs to move after the
21353          * mousedown before the drag is initiated.  Default=3;
21354          * @property clickPixelThresh
21355          * @type int
21356          * @static
21357          */
21358         clickPixelThresh: 3,
21359
21360         /**
21361          * The number of milliseconds after the mousedown event to initiate the
21362          * drag if we don't get a mouseup event. Default=1000
21363          * @property clickTimeThresh
21364          * @type int
21365          * @static
21366          */
21367         clickTimeThresh: 350,
21368
21369         /**
21370          * Flag that indicates that either the drag pixel threshold or the
21371          * mousdown time threshold has been met
21372          * @property dragThreshMet
21373          * @type boolean
21374          * @private
21375          * @static
21376          */
21377         dragThreshMet: false,
21378
21379         /**
21380          * Timeout used for the click time threshold
21381          * @property clickTimeout
21382          * @type Object
21383          * @private
21384          * @static
21385          */
21386         clickTimeout: null,
21387
21388         /**
21389          * The X position of the mousedown event stored for later use when a
21390          * drag threshold is met.
21391          * @property startX
21392          * @type int
21393          * @private
21394          * @static
21395          */
21396         startX: 0,
21397
21398         /**
21399          * The Y position of the mousedown event stored for later use when a
21400          * drag threshold is met.
21401          * @property startY
21402          * @type int
21403          * @private
21404          * @static
21405          */
21406         startY: 0,
21407
21408         /**
21409          * Each DragDrop instance must be registered with the DragDropMgr.
21410          * This is executed in DragDrop.init()
21411          * @method regDragDrop
21412          * @param {DragDrop} oDD the DragDrop object to register
21413          * @param {String} sGroup the name of the group this element belongs to
21414          * @static
21415          */
21416         regDragDrop: function(oDD, sGroup) {
21417             if (!this.initialized) { this.init(); }
21418
21419             if (!this.ids[sGroup]) {
21420                 this.ids[sGroup] = {};
21421             }
21422             this.ids[sGroup][oDD.id] = oDD;
21423         },
21424
21425         /**
21426          * Removes the supplied dd instance from the supplied group. Executed
21427          * by DragDrop.removeFromGroup, so don't call this function directly.
21428          * @method removeDDFromGroup
21429          * @private
21430          * @static
21431          */
21432         removeDDFromGroup: function(oDD, sGroup) {
21433             if (!this.ids[sGroup]) {
21434                 this.ids[sGroup] = {};
21435             }
21436
21437             var obj = this.ids[sGroup];
21438             if (obj && obj[oDD.id]) {
21439                 delete obj[oDD.id];
21440             }
21441         },
21442
21443         /**
21444          * Unregisters a drag and drop item.  This is executed in
21445          * DragDrop.unreg, use that method instead of calling this directly.
21446          * @method _remove
21447          * @private
21448          * @static
21449          */
21450         _remove: function(oDD) {
21451             for (var g in oDD.groups) {
21452                 if (g && this.ids[g][oDD.id]) {
21453                     delete this.ids[g][oDD.id];
21454                 }
21455             }
21456             delete this.handleIds[oDD.id];
21457         },
21458
21459         /**
21460          * Each DragDrop handle element must be registered.  This is done
21461          * automatically when executing DragDrop.setHandleElId()
21462          * @method regHandle
21463          * @param {String} sDDId the DragDrop id this element is a handle for
21464          * @param {String} sHandleId the id of the element that is the drag
21465          * handle
21466          * @static
21467          */
21468         regHandle: function(sDDId, sHandleId) {
21469             if (!this.handleIds[sDDId]) {
21470                 this.handleIds[sDDId] = {};
21471             }
21472             this.handleIds[sDDId][sHandleId] = sHandleId;
21473         },
21474
21475         /**
21476          * Utility function to determine if a given element has been
21477          * registered as a drag drop item.
21478          * @method isDragDrop
21479          * @param {String} id the element id to check
21480          * @return {boolean} true if this element is a DragDrop item,
21481          * false otherwise
21482          * @static
21483          */
21484         isDragDrop: function(id) {
21485             return ( this.getDDById(id) ) ? true : false;
21486         },
21487
21488         /**
21489          * Returns the drag and drop instances that are in all groups the
21490          * passed in instance belongs to.
21491          * @method getRelated
21492          * @param {DragDrop} p_oDD the obj to get related data for
21493          * @param {boolean} bTargetsOnly if true, only return targetable objs
21494          * @return {DragDrop[]} the related instances
21495          * @static
21496          */
21497         getRelated: function(p_oDD, bTargetsOnly) {
21498             var oDDs = [];
21499             for (var i in p_oDD.groups) {
21500                 for (j in this.ids[i]) {
21501                     var dd = this.ids[i][j];
21502                     if (! this.isTypeOfDD(dd)) {
21503                         continue;
21504                     }
21505                     if (!bTargetsOnly || dd.isTarget) {
21506                         oDDs[oDDs.length] = dd;
21507                     }
21508                 }
21509             }
21510
21511             return oDDs;
21512         },
21513
21514         /**
21515          * Returns true if the specified dd target is a legal target for
21516          * the specifice drag obj
21517          * @method isLegalTarget
21518          * @param {DragDrop} the drag obj
21519          * @param {DragDrop} the target
21520          * @return {boolean} true if the target is a legal target for the
21521          * dd obj
21522          * @static
21523          */
21524         isLegalTarget: function (oDD, oTargetDD) {
21525             var targets = this.getRelated(oDD, true);
21526             for (var i=0, len=targets.length;i<len;++i) {
21527                 if (targets[i].id == oTargetDD.id) {
21528                     return true;
21529                 }
21530             }
21531
21532             return false;
21533         },
21534
21535         /**
21536          * My goal is to be able to transparently determine if an object is
21537          * typeof DragDrop, and the exact subclass of DragDrop.  typeof
21538          * returns "object", oDD.constructor.toString() always returns
21539          * "DragDrop" and not the name of the subclass.  So for now it just
21540          * evaluates a well-known variable in DragDrop.
21541          * @method isTypeOfDD
21542          * @param {Object} the object to evaluate
21543          * @return {boolean} true if typeof oDD = DragDrop
21544          * @static
21545          */
21546         isTypeOfDD: function (oDD) {
21547             return (oDD && oDD.__ygDragDrop);
21548         },
21549
21550         /**
21551          * Utility function to determine if a given element has been
21552          * registered as a drag drop handle for the given Drag Drop object.
21553          * @method isHandle
21554          * @param {String} id the element id to check
21555          * @return {boolean} true if this element is a DragDrop handle, false
21556          * otherwise
21557          * @static
21558          */
21559         isHandle: function(sDDId, sHandleId) {
21560             return ( this.handleIds[sDDId] &&
21561                             this.handleIds[sDDId][sHandleId] );
21562         },
21563
21564         /**
21565          * Returns the DragDrop instance for a given id
21566          * @method getDDById
21567          * @param {String} id the id of the DragDrop object
21568          * @return {DragDrop} the drag drop object, null if it is not found
21569          * @static
21570          */
21571         getDDById: function(id) {
21572             for (var i in this.ids) {
21573                 if (this.ids[i][id]) {
21574                     return this.ids[i][id];
21575                 }
21576             }
21577             return null;
21578         },
21579
21580         /**
21581          * Fired after a registered DragDrop object gets the mousedown event.
21582          * Sets up the events required to track the object being dragged
21583          * @method handleMouseDown
21584          * @param {Event} e the event
21585          * @param oDD the DragDrop object being dragged
21586          * @private
21587          * @static
21588          */
21589         handleMouseDown: function(e, oDD) {
21590             if(Roo.QuickTips){
21591                 Roo.QuickTips.disable();
21592             }
21593             this.currentTarget = e.getTarget();
21594
21595             this.dragCurrent = oDD;
21596
21597             var el = oDD.getEl();
21598
21599             // track start position
21600             this.startX = e.getPageX();
21601             this.startY = e.getPageY();
21602
21603             this.deltaX = this.startX - el.offsetLeft;
21604             this.deltaY = this.startY - el.offsetTop;
21605
21606             this.dragThreshMet = false;
21607
21608             this.clickTimeout = setTimeout(
21609                     function() {
21610                         var DDM = Roo.dd.DDM;
21611                         DDM.startDrag(DDM.startX, DDM.startY);
21612                     },
21613                     this.clickTimeThresh );
21614         },
21615
21616         /**
21617          * Fired when either the drag pixel threshol or the mousedown hold
21618          * time threshold has been met.
21619          * @method startDrag
21620          * @param x {int} the X position of the original mousedown
21621          * @param y {int} the Y position of the original mousedown
21622          * @static
21623          */
21624         startDrag: function(x, y) {
21625             clearTimeout(this.clickTimeout);
21626             if (this.dragCurrent) {
21627                 this.dragCurrent.b4StartDrag(x, y);
21628                 this.dragCurrent.startDrag(x, y);
21629             }
21630             this.dragThreshMet = true;
21631         },
21632
21633         /**
21634          * Internal function to handle the mouseup event.  Will be invoked
21635          * from the context of the document.
21636          * @method handleMouseUp
21637          * @param {Event} e the event
21638          * @private
21639          * @static
21640          */
21641         handleMouseUp: function(e) {
21642
21643             if(Roo.QuickTips){
21644                 Roo.QuickTips.enable();
21645             }
21646             if (! this.dragCurrent) {
21647                 return;
21648             }
21649
21650             clearTimeout(this.clickTimeout);
21651
21652             if (this.dragThreshMet) {
21653                 this.fireEvents(e, true);
21654             } else {
21655             }
21656
21657             this.stopDrag(e);
21658
21659             this.stopEvent(e);
21660         },
21661
21662         /**
21663          * Utility to stop event propagation and event default, if these
21664          * features are turned on.
21665          * @method stopEvent
21666          * @param {Event} e the event as returned by this.getEvent()
21667          * @static
21668          */
21669         stopEvent: function(e){
21670             if(this.stopPropagation) {
21671                 e.stopPropagation();
21672             }
21673
21674             if (this.preventDefault) {
21675                 e.preventDefault();
21676             }
21677         },
21678
21679         /**
21680          * Internal function to clean up event handlers after the drag
21681          * operation is complete
21682          * @method stopDrag
21683          * @param {Event} e the event
21684          * @private
21685          * @static
21686          */
21687         stopDrag: function(e) {
21688             // Fire the drag end event for the item that was dragged
21689             if (this.dragCurrent) {
21690                 if (this.dragThreshMet) {
21691                     this.dragCurrent.b4EndDrag(e);
21692                     this.dragCurrent.endDrag(e);
21693                 }
21694
21695                 this.dragCurrent.onMouseUp(e);
21696             }
21697
21698             this.dragCurrent = null;
21699             this.dragOvers = {};
21700         },
21701
21702         /**
21703          * Internal function to handle the mousemove event.  Will be invoked
21704          * from the context of the html element.
21705          *
21706          * @TODO figure out what we can do about mouse events lost when the
21707          * user drags objects beyond the window boundary.  Currently we can
21708          * detect this in internet explorer by verifying that the mouse is
21709          * down during the mousemove event.  Firefox doesn't give us the
21710          * button state on the mousemove event.
21711          * @method handleMouseMove
21712          * @param {Event} e the event
21713          * @private
21714          * @static
21715          */
21716         handleMouseMove: function(e) {
21717             if (! this.dragCurrent) {
21718                 return true;
21719             }
21720
21721             // var button = e.which || e.button;
21722
21723             // check for IE mouseup outside of page boundary
21724             if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
21725                 this.stopEvent(e);
21726                 return this.handleMouseUp(e);
21727             }
21728
21729             if (!this.dragThreshMet) {
21730                 var diffX = Math.abs(this.startX - e.getPageX());
21731                 var diffY = Math.abs(this.startY - e.getPageY());
21732                 if (diffX > this.clickPixelThresh ||
21733                             diffY > this.clickPixelThresh) {
21734                     this.startDrag(this.startX, this.startY);
21735                 }
21736             }
21737
21738             if (this.dragThreshMet) {
21739                 this.dragCurrent.b4Drag(e);
21740                 this.dragCurrent.onDrag(e);
21741                 if(!this.dragCurrent.moveOnly){
21742                     this.fireEvents(e, false);
21743                 }
21744             }
21745
21746             this.stopEvent(e);
21747
21748             return true;
21749         },
21750
21751         /**
21752          * Iterates over all of the DragDrop elements to find ones we are
21753          * hovering over or dropping on
21754          * @method fireEvents
21755          * @param {Event} e the event
21756          * @param {boolean} isDrop is this a drop op or a mouseover op?
21757          * @private
21758          * @static
21759          */
21760         fireEvents: function(e, isDrop) {
21761             var dc = this.dragCurrent;
21762
21763             // If the user did the mouse up outside of the window, we could
21764             // get here even though we have ended the drag.
21765             if (!dc || dc.isLocked()) {
21766                 return;
21767             }
21768
21769             var pt = e.getPoint();
21770
21771             // cache the previous dragOver array
21772             var oldOvers = [];
21773
21774             var outEvts   = [];
21775             var overEvts  = [];
21776             var dropEvts  = [];
21777             var enterEvts = [];
21778
21779             // Check to see if the object(s) we were hovering over is no longer
21780             // being hovered over so we can fire the onDragOut event
21781             for (var i in this.dragOvers) {
21782
21783                 var ddo = this.dragOvers[i];
21784
21785                 if (! this.isTypeOfDD(ddo)) {
21786                     continue;
21787                 }
21788
21789                 if (! this.isOverTarget(pt, ddo, this.mode)) {
21790                     outEvts.push( ddo );
21791                 }
21792
21793                 oldOvers[i] = true;
21794                 delete this.dragOvers[i];
21795             }
21796
21797             for (var sGroup in dc.groups) {
21798
21799                 if ("string" != typeof sGroup) {
21800                     continue;
21801                 }
21802
21803                 for (i in this.ids[sGroup]) {
21804                     var oDD = this.ids[sGroup][i];
21805                     if (! this.isTypeOfDD(oDD)) {
21806                         continue;
21807                     }
21808
21809                     if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
21810                         if (this.isOverTarget(pt, oDD, this.mode)) {
21811                             // look for drop interactions
21812                             if (isDrop) {
21813                                 dropEvts.push( oDD );
21814                             // look for drag enter and drag over interactions
21815                             } else {
21816
21817                                 // initial drag over: dragEnter fires
21818                                 if (!oldOvers[oDD.id]) {
21819                                     enterEvts.push( oDD );
21820                                 // subsequent drag overs: dragOver fires
21821                                 } else {
21822                                     overEvts.push( oDD );
21823                                 }
21824
21825                                 this.dragOvers[oDD.id] = oDD;
21826                             }
21827                         }
21828                     }
21829                 }
21830             }
21831
21832             if (this.mode) {
21833                 if (outEvts.length) {
21834                     dc.b4DragOut(e, outEvts);
21835                     dc.onDragOut(e, outEvts);
21836                 }
21837
21838                 if (enterEvts.length) {
21839                     dc.onDragEnter(e, enterEvts);
21840                 }
21841
21842                 if (overEvts.length) {
21843                     dc.b4DragOver(e, overEvts);
21844                     dc.onDragOver(e, overEvts);
21845                 }
21846
21847                 if (dropEvts.length) {
21848                     dc.b4DragDrop(e, dropEvts);
21849                     dc.onDragDrop(e, dropEvts);
21850                 }
21851
21852             } else {
21853                 // fire dragout events
21854                 var len = 0;
21855                 for (i=0, len=outEvts.length; i<len; ++i) {
21856                     dc.b4DragOut(e, outEvts[i].id);
21857                     dc.onDragOut(e, outEvts[i].id);
21858                 }
21859
21860                 // fire enter events
21861                 for (i=0,len=enterEvts.length; i<len; ++i) {
21862                     // dc.b4DragEnter(e, oDD.id);
21863                     dc.onDragEnter(e, enterEvts[i].id);
21864                 }
21865
21866                 // fire over events
21867                 for (i=0,len=overEvts.length; i<len; ++i) {
21868                     dc.b4DragOver(e, overEvts[i].id);
21869                     dc.onDragOver(e, overEvts[i].id);
21870                 }
21871
21872                 // fire drop events
21873                 for (i=0, len=dropEvts.length; i<len; ++i) {
21874                     dc.b4DragDrop(e, dropEvts[i].id);
21875                     dc.onDragDrop(e, dropEvts[i].id);
21876                 }
21877
21878             }
21879
21880             // notify about a drop that did not find a target
21881             if (isDrop && !dropEvts.length) {
21882                 dc.onInvalidDrop(e);
21883             }
21884
21885         },
21886
21887         /**
21888          * Helper function for getting the best match from the list of drag
21889          * and drop objects returned by the drag and drop events when we are
21890          * in INTERSECT mode.  It returns either the first object that the
21891          * cursor is over, or the object that has the greatest overlap with
21892          * the dragged element.
21893          * @method getBestMatch
21894          * @param  {DragDrop[]} dds The array of drag and drop objects
21895          * targeted
21896          * @return {DragDrop}       The best single match
21897          * @static
21898          */
21899         getBestMatch: function(dds) {
21900             var winner = null;
21901             // Return null if the input is not what we expect
21902             //if (!dds || !dds.length || dds.length == 0) {
21903                // winner = null;
21904             // If there is only one item, it wins
21905             //} else if (dds.length == 1) {
21906
21907             var len = dds.length;
21908
21909             if (len == 1) {
21910                 winner = dds[0];
21911             } else {
21912                 // Loop through the targeted items
21913                 for (var i=0; i<len; ++i) {
21914                     var dd = dds[i];
21915                     // If the cursor is over the object, it wins.  If the
21916                     // cursor is over multiple matches, the first one we come
21917                     // to wins.
21918                     if (dd.cursorIsOver) {
21919                         winner = dd;
21920                         break;
21921                     // Otherwise the object with the most overlap wins
21922                     } else {
21923                         if (!winner ||
21924                             winner.overlap.getArea() < dd.overlap.getArea()) {
21925                             winner = dd;
21926                         }
21927                     }
21928                 }
21929             }
21930
21931             return winner;
21932         },
21933
21934         /**
21935          * Refreshes the cache of the top-left and bottom-right points of the
21936          * drag and drop objects in the specified group(s).  This is in the
21937          * format that is stored in the drag and drop instance, so typical
21938          * usage is:
21939          * <code>
21940          * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
21941          * </code>
21942          * Alternatively:
21943          * <code>
21944          * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
21945          * </code>
21946          * @TODO this really should be an indexed array.  Alternatively this
21947          * method could accept both.
21948          * @method refreshCache
21949          * @param {Object} groups an associative array of groups to refresh
21950          * @static
21951          */
21952         refreshCache: function(groups) {
21953             for (var sGroup in groups) {
21954                 if ("string" != typeof sGroup) {
21955                     continue;
21956                 }
21957                 for (var i in this.ids[sGroup]) {
21958                     var oDD = this.ids[sGroup][i];
21959
21960                     if (this.isTypeOfDD(oDD)) {
21961                     // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
21962                         var loc = this.getLocation(oDD);
21963                         if (loc) {
21964                             this.locationCache[oDD.id] = loc;
21965                         } else {
21966                             delete this.locationCache[oDD.id];
21967                             // this will unregister the drag and drop object if
21968                             // the element is not in a usable state
21969                             // oDD.unreg();
21970                         }
21971                     }
21972                 }
21973             }
21974         },
21975
21976         /**
21977          * This checks to make sure an element exists and is in the DOM.  The
21978          * main purpose is to handle cases where innerHTML is used to remove
21979          * drag and drop objects from the DOM.  IE provides an 'unspecified
21980          * error' when trying to access the offsetParent of such an element
21981          * @method verifyEl
21982          * @param {HTMLElement} el the element to check
21983          * @return {boolean} true if the element looks usable
21984          * @static
21985          */
21986         verifyEl: function(el) {
21987             if (el) {
21988                 var parent;
21989                 if(Roo.isIE){
21990                     try{
21991                         parent = el.offsetParent;
21992                     }catch(e){}
21993                 }else{
21994                     parent = el.offsetParent;
21995                 }
21996                 if (parent) {
21997                     return true;
21998                 }
21999             }
22000
22001             return false;
22002         },
22003
22004         /**
22005          * Returns a Region object containing the drag and drop element's position
22006          * and size, including the padding configured for it
22007          * @method getLocation
22008          * @param {DragDrop} oDD the drag and drop object to get the
22009          *                       location for
22010          * @return {Roo.lib.Region} a Region object representing the total area
22011          *                             the element occupies, including any padding
22012          *                             the instance is configured for.
22013          * @static
22014          */
22015         getLocation: function(oDD) {
22016             if (! this.isTypeOfDD(oDD)) {
22017                 return null;
22018             }
22019
22020             var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
22021
22022             try {
22023                 pos= Roo.lib.Dom.getXY(el);
22024             } catch (e) { }
22025
22026             if (!pos) {
22027                 return null;
22028             }
22029
22030             x1 = pos[0];
22031             x2 = x1 + el.offsetWidth;
22032             y1 = pos[1];
22033             y2 = y1 + el.offsetHeight;
22034
22035             t = y1 - oDD.padding[0];
22036             r = x2 + oDD.padding[1];
22037             b = y2 + oDD.padding[2];
22038             l = x1 - oDD.padding[3];
22039
22040             return new Roo.lib.Region( t, r, b, l );
22041         },
22042
22043         /**
22044          * Checks the cursor location to see if it over the target
22045          * @method isOverTarget
22046          * @param {Roo.lib.Point} pt The point to evaluate
22047          * @param {DragDrop} oTarget the DragDrop object we are inspecting
22048          * @return {boolean} true if the mouse is over the target
22049          * @private
22050          * @static
22051          */
22052         isOverTarget: function(pt, oTarget, intersect) {
22053             // use cache if available
22054             var loc = this.locationCache[oTarget.id];
22055             if (!loc || !this.useCache) {
22056                 loc = this.getLocation(oTarget);
22057                 this.locationCache[oTarget.id] = loc;
22058
22059             }
22060
22061             if (!loc) {
22062                 return false;
22063             }
22064
22065             oTarget.cursorIsOver = loc.contains( pt );
22066
22067             // DragDrop is using this as a sanity check for the initial mousedown
22068             // in this case we are done.  In POINT mode, if the drag obj has no
22069             // contraints, we are also done. Otherwise we need to evaluate the
22070             // location of the target as related to the actual location of the
22071             // dragged element.
22072             var dc = this.dragCurrent;
22073             if (!dc || !dc.getTargetCoord ||
22074                     (!intersect && !dc.constrainX && !dc.constrainY)) {
22075                 return oTarget.cursorIsOver;
22076             }
22077
22078             oTarget.overlap = null;
22079
22080             // Get the current location of the drag element, this is the
22081             // location of the mouse event less the delta that represents
22082             // where the original mousedown happened on the element.  We
22083             // need to consider constraints and ticks as well.
22084             var pos = dc.getTargetCoord(pt.x, pt.y);
22085
22086             var el = dc.getDragEl();
22087             var curRegion = new Roo.lib.Region( pos.y,
22088                                                    pos.x + el.offsetWidth,
22089                                                    pos.y + el.offsetHeight,
22090                                                    pos.x );
22091
22092             var overlap = curRegion.intersect(loc);
22093
22094             if (overlap) {
22095                 oTarget.overlap = overlap;
22096                 return (intersect) ? true : oTarget.cursorIsOver;
22097             } else {
22098                 return false;
22099             }
22100         },
22101
22102         /**
22103          * unload event handler
22104          * @method _onUnload
22105          * @private
22106          * @static
22107          */
22108         _onUnload: function(e, me) {
22109             Roo.dd.DragDropMgr.unregAll();
22110         },
22111
22112         /**
22113          * Cleans up the drag and drop events and objects.
22114          * @method unregAll
22115          * @private
22116          * @static
22117          */
22118         unregAll: function() {
22119
22120             if (this.dragCurrent) {
22121                 this.stopDrag();
22122                 this.dragCurrent = null;
22123             }
22124
22125             this._execOnAll("unreg", []);
22126
22127             for (i in this.elementCache) {
22128                 delete this.elementCache[i];
22129             }
22130
22131             this.elementCache = {};
22132             this.ids = {};
22133         },
22134
22135         /**
22136          * A cache of DOM elements
22137          * @property elementCache
22138          * @private
22139          * @static
22140          */
22141         elementCache: {},
22142
22143         /**
22144          * Get the wrapper for the DOM element specified
22145          * @method getElWrapper
22146          * @param {String} id the id of the element to get
22147          * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
22148          * @private
22149          * @deprecated This wrapper isn't that useful
22150          * @static
22151          */
22152         getElWrapper: function(id) {
22153             var oWrapper = this.elementCache[id];
22154             if (!oWrapper || !oWrapper.el) {
22155                 oWrapper = this.elementCache[id] =
22156                     new this.ElementWrapper(Roo.getDom(id));
22157             }
22158             return oWrapper;
22159         },
22160
22161         /**
22162          * Returns the actual DOM element
22163          * @method getElement
22164          * @param {String} id the id of the elment to get
22165          * @return {Object} The element
22166          * @deprecated use Roo.getDom instead
22167          * @static
22168          */
22169         getElement: function(id) {
22170             return Roo.getDom(id);
22171         },
22172
22173         /**
22174          * Returns the style property for the DOM element (i.e.,
22175          * document.getElById(id).style)
22176          * @method getCss
22177          * @param {String} id the id of the elment to get
22178          * @return {Object} The style property of the element
22179          * @deprecated use Roo.getDom instead
22180          * @static
22181          */
22182         getCss: function(id) {
22183             var el = Roo.getDom(id);
22184             return (el) ? el.style : null;
22185         },
22186
22187         /**
22188          * Inner class for cached elements
22189          * @class DragDropMgr.ElementWrapper
22190          * @for DragDropMgr
22191          * @private
22192          * @deprecated
22193          */
22194         ElementWrapper: function(el) {
22195                 /**
22196                  * The element
22197                  * @property el
22198                  */
22199                 this.el = el || null;
22200                 /**
22201                  * The element id
22202                  * @property id
22203                  */
22204                 this.id = this.el && el.id;
22205                 /**
22206                  * A reference to the style property
22207                  * @property css
22208                  */
22209                 this.css = this.el && el.style;
22210             },
22211
22212         /**
22213          * Returns the X position of an html element
22214          * @method getPosX
22215          * @param el the element for which to get the position
22216          * @return {int} the X coordinate
22217          * @for DragDropMgr
22218          * @deprecated use Roo.lib.Dom.getX instead
22219          * @static
22220          */
22221         getPosX: function(el) {
22222             return Roo.lib.Dom.getX(el);
22223         },
22224
22225         /**
22226          * Returns the Y position of an html element
22227          * @method getPosY
22228          * @param el the element for which to get the position
22229          * @return {int} the Y coordinate
22230          * @deprecated use Roo.lib.Dom.getY instead
22231          * @static
22232          */
22233         getPosY: function(el) {
22234             return Roo.lib.Dom.getY(el);
22235         },
22236
22237         /**
22238          * Swap two nodes.  In IE, we use the native method, for others we
22239          * emulate the IE behavior
22240          * @method swapNode
22241          * @param n1 the first node to swap
22242          * @param n2 the other node to swap
22243          * @static
22244          */
22245         swapNode: function(n1, n2) {
22246             if (n1.swapNode) {
22247                 n1.swapNode(n2);
22248             } else {
22249                 var p = n2.parentNode;
22250                 var s = n2.nextSibling;
22251
22252                 if (s == n1) {
22253                     p.insertBefore(n1, n2);
22254                 } else if (n2 == n1.nextSibling) {
22255                     p.insertBefore(n2, n1);
22256                 } else {
22257                     n1.parentNode.replaceChild(n2, n1);
22258                     p.insertBefore(n1, s);
22259                 }
22260             }
22261         },
22262
22263         /**
22264          * Returns the current scroll position
22265          * @method getScroll
22266          * @private
22267          * @static
22268          */
22269         getScroll: function () {
22270             var t, l, dde=document.documentElement, db=document.body;
22271             if (dde && (dde.scrollTop || dde.scrollLeft)) {
22272                 t = dde.scrollTop;
22273                 l = dde.scrollLeft;
22274             } else if (db) {
22275                 t = db.scrollTop;
22276                 l = db.scrollLeft;
22277             } else {
22278
22279             }
22280             return { top: t, left: l };
22281         },
22282
22283         /**
22284          * Returns the specified element style property
22285          * @method getStyle
22286          * @param {HTMLElement} el          the element
22287          * @param {string}      styleProp   the style property
22288          * @return {string} The value of the style property
22289          * @deprecated use Roo.lib.Dom.getStyle
22290          * @static
22291          */
22292         getStyle: function(el, styleProp) {
22293             return Roo.fly(el).getStyle(styleProp);
22294         },
22295
22296         /**
22297          * Gets the scrollTop
22298          * @method getScrollTop
22299          * @return {int} the document's scrollTop
22300          * @static
22301          */
22302         getScrollTop: function () { return this.getScroll().top; },
22303
22304         /**
22305          * Gets the scrollLeft
22306          * @method getScrollLeft
22307          * @return {int} the document's scrollTop
22308          * @static
22309          */
22310         getScrollLeft: function () { return this.getScroll().left; },
22311
22312         /**
22313          * Sets the x/y position of an element to the location of the
22314          * target element.
22315          * @method moveToEl
22316          * @param {HTMLElement} moveEl      The element to move
22317          * @param {HTMLElement} targetEl    The position reference element
22318          * @static
22319          */
22320         moveToEl: function (moveEl, targetEl) {
22321             var aCoord = Roo.lib.Dom.getXY(targetEl);
22322             Roo.lib.Dom.setXY(moveEl, aCoord);
22323         },
22324
22325         /**
22326          * Numeric array sort function
22327          * @method numericSort
22328          * @static
22329          */
22330         numericSort: function(a, b) { return (a - b); },
22331
22332         /**
22333          * Internal counter
22334          * @property _timeoutCount
22335          * @private
22336          * @static
22337          */
22338         _timeoutCount: 0,
22339
22340         /**
22341          * Trying to make the load order less important.  Without this we get
22342          * an error if this file is loaded before the Event Utility.
22343          * @method _addListeners
22344          * @private
22345          * @static
22346          */
22347         _addListeners: function() {
22348             var DDM = Roo.dd.DDM;
22349             if ( Roo.lib.Event && document ) {
22350                 DDM._onLoad();
22351             } else {
22352                 if (DDM._timeoutCount > 2000) {
22353                 } else {
22354                     setTimeout(DDM._addListeners, 10);
22355                     if (document && document.body) {
22356                         DDM._timeoutCount += 1;
22357                     }
22358                 }
22359             }
22360         },
22361
22362         /**
22363          * Recursively searches the immediate parent and all child nodes for
22364          * the handle element in order to determine wheter or not it was
22365          * clicked.
22366          * @method handleWasClicked
22367          * @param node the html element to inspect
22368          * @static
22369          */
22370         handleWasClicked: function(node, id) {
22371             if (this.isHandle(id, node.id)) {
22372                 return true;
22373             } else {
22374                 // check to see if this is a text node child of the one we want
22375                 var p = node.parentNode;
22376
22377                 while (p) {
22378                     if (this.isHandle(id, p.id)) {
22379                         return true;
22380                     } else {
22381                         p = p.parentNode;
22382                     }
22383                 }
22384             }
22385
22386             return false;
22387         }
22388
22389     };
22390
22391 }();
22392
22393 // shorter alias, save a few bytes
22394 Roo.dd.DDM = Roo.dd.DragDropMgr;
22395 Roo.dd.DDM._addListeners();
22396
22397 }/*
22398  * Based on:
22399  * Ext JS Library 1.1.1
22400  * Copyright(c) 2006-2007, Ext JS, LLC.
22401  *
22402  * Originally Released Under LGPL - original licence link has changed is not relivant.
22403  *
22404  * Fork - LGPL
22405  * <script type="text/javascript">
22406  */
22407
22408 /**
22409  * @class Roo.dd.DD
22410  * A DragDrop implementation where the linked element follows the
22411  * mouse cursor during a drag.
22412  * @extends Roo.dd.DragDrop
22413  * @constructor
22414  * @param {String} id the id of the linked element
22415  * @param {String} sGroup the group of related DragDrop items
22416  * @param {object} config an object containing configurable attributes
22417  *                Valid properties for DD:
22418  *                    scroll
22419  */
22420 Roo.dd.DD = function(id, sGroup, config) {
22421     if (id) {
22422         this.init(id, sGroup, config);
22423     }
22424 };
22425
22426 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
22427
22428     /**
22429      * When set to true, the utility automatically tries to scroll the browser
22430      * window wehn a drag and drop element is dragged near the viewport boundary.
22431      * Defaults to true.
22432      * @property scroll
22433      * @type boolean
22434      */
22435     scroll: true,
22436
22437     /**
22438      * Sets the pointer offset to the distance between the linked element's top
22439      * left corner and the location the element was clicked
22440      * @method autoOffset
22441      * @param {int} iPageX the X coordinate of the click
22442      * @param {int} iPageY the Y coordinate of the click
22443      */
22444     autoOffset: function(iPageX, iPageY) {
22445         var x = iPageX - this.startPageX;
22446         var y = iPageY - this.startPageY;
22447         this.setDelta(x, y);
22448     },
22449
22450     /**
22451      * Sets the pointer offset.  You can call this directly to force the
22452      * offset to be in a particular location (e.g., pass in 0,0 to set it
22453      * to the center of the object)
22454      * @method setDelta
22455      * @param {int} iDeltaX the distance from the left
22456      * @param {int} iDeltaY the distance from the top
22457      */
22458     setDelta: function(iDeltaX, iDeltaY) {
22459         this.deltaX = iDeltaX;
22460         this.deltaY = iDeltaY;
22461     },
22462
22463     /**
22464      * Sets the drag element to the location of the mousedown or click event,
22465      * maintaining the cursor location relative to the location on the element
22466      * that was clicked.  Override this if you want to place the element in a
22467      * location other than where the cursor is.
22468      * @method setDragElPos
22469      * @param {int} iPageX the X coordinate of the mousedown or drag event
22470      * @param {int} iPageY the Y coordinate of the mousedown or drag event
22471      */
22472     setDragElPos: function(iPageX, iPageY) {
22473         // the first time we do this, we are going to check to make sure
22474         // the element has css positioning
22475
22476         var el = this.getDragEl();
22477         this.alignElWithMouse(el, iPageX, iPageY);
22478     },
22479
22480     /**
22481      * Sets the element to the location of the mousedown or click event,
22482      * maintaining the cursor location relative to the location on the element
22483      * that was clicked.  Override this if you want to place the element in a
22484      * location other than where the cursor is.
22485      * @method alignElWithMouse
22486      * @param {HTMLElement} el the element to move
22487      * @param {int} iPageX the X coordinate of the mousedown or drag event
22488      * @param {int} iPageY the Y coordinate of the mousedown or drag event
22489      */
22490     alignElWithMouse: function(el, iPageX, iPageY) {
22491         var oCoord = this.getTargetCoord(iPageX, iPageY);
22492         var fly = el.dom ? el : Roo.fly(el);
22493         if (!this.deltaSetXY) {
22494             var aCoord = [oCoord.x, oCoord.y];
22495             fly.setXY(aCoord);
22496             var newLeft = fly.getLeft(true);
22497             var newTop  = fly.getTop(true);
22498             this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
22499         } else {
22500             fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
22501         }
22502
22503         this.cachePosition(oCoord.x, oCoord.y);
22504         this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
22505         return oCoord;
22506     },
22507
22508     /**
22509      * Saves the most recent position so that we can reset the constraints and
22510      * tick marks on-demand.  We need to know this so that we can calculate the
22511      * number of pixels the element is offset from its original position.
22512      * @method cachePosition
22513      * @param iPageX the current x position (optional, this just makes it so we
22514      * don't have to look it up again)
22515      * @param iPageY the current y position (optional, this just makes it so we
22516      * don't have to look it up again)
22517      */
22518     cachePosition: function(iPageX, iPageY) {
22519         if (iPageX) {
22520             this.lastPageX = iPageX;
22521             this.lastPageY = iPageY;
22522         } else {
22523             var aCoord = Roo.lib.Dom.getXY(this.getEl());
22524             this.lastPageX = aCoord[0];
22525             this.lastPageY = aCoord[1];
22526         }
22527     },
22528
22529     /**
22530      * Auto-scroll the window if the dragged object has been moved beyond the
22531      * visible window boundary.
22532      * @method autoScroll
22533      * @param {int} x the drag element's x position
22534      * @param {int} y the drag element's y position
22535      * @param {int} h the height of the drag element
22536      * @param {int} w the width of the drag element
22537      * @private
22538      */
22539     autoScroll: function(x, y, h, w) {
22540
22541         if (this.scroll) {
22542             // The client height
22543             var clientH = Roo.lib.Dom.getViewWidth();
22544
22545             // The client width
22546             var clientW = Roo.lib.Dom.getViewHeight();
22547
22548             // The amt scrolled down
22549             var st = this.DDM.getScrollTop();
22550
22551             // The amt scrolled right
22552             var sl = this.DDM.getScrollLeft();
22553
22554             // Location of the bottom of the element
22555             var bot = h + y;
22556
22557             // Location of the right of the element
22558             var right = w + x;
22559
22560             // The distance from the cursor to the bottom of the visible area,
22561             // adjusted so that we don't scroll if the cursor is beyond the
22562             // element drag constraints
22563             var toBot = (clientH + st - y - this.deltaY);
22564
22565             // The distance from the cursor to the right of the visible area
22566             var toRight = (clientW + sl - x - this.deltaX);
22567
22568
22569             // How close to the edge the cursor must be before we scroll
22570             // var thresh = (document.all) ? 100 : 40;
22571             var thresh = 40;
22572
22573             // How many pixels to scroll per autoscroll op.  This helps to reduce
22574             // clunky scrolling. IE is more sensitive about this ... it needs this
22575             // value to be higher.
22576             var scrAmt = (document.all) ? 80 : 30;
22577
22578             // Scroll down if we are near the bottom of the visible page and the
22579             // obj extends below the crease
22580             if ( bot > clientH && toBot < thresh ) {
22581                 window.scrollTo(sl, st + scrAmt);
22582             }
22583
22584             // Scroll up if the window is scrolled down and the top of the object
22585             // goes above the top border
22586             if ( y < st && st > 0 && y - st < thresh ) {
22587                 window.scrollTo(sl, st - scrAmt);
22588             }
22589
22590             // Scroll right if the obj is beyond the right border and the cursor is
22591             // near the border.
22592             if ( right > clientW && toRight < thresh ) {
22593                 window.scrollTo(sl + scrAmt, st);
22594             }
22595
22596             // Scroll left if the window has been scrolled to the right and the obj
22597             // extends past the left border
22598             if ( x < sl && sl > 0 && x - sl < thresh ) {
22599                 window.scrollTo(sl - scrAmt, st);
22600             }
22601         }
22602     },
22603
22604     /**
22605      * Finds the location the element should be placed if we want to move
22606      * it to where the mouse location less the click offset would place us.
22607      * @method getTargetCoord
22608      * @param {int} iPageX the X coordinate of the click
22609      * @param {int} iPageY the Y coordinate of the click
22610      * @return an object that contains the coordinates (Object.x and Object.y)
22611      * @private
22612      */
22613     getTargetCoord: function(iPageX, iPageY) {
22614
22615
22616         var x = iPageX - this.deltaX;
22617         var y = iPageY - this.deltaY;
22618
22619         if (this.constrainX) {
22620             if (x < this.minX) { x = this.minX; }
22621             if (x > this.maxX) { x = this.maxX; }
22622         }
22623
22624         if (this.constrainY) {
22625             if (y < this.minY) { y = this.minY; }
22626             if (y > this.maxY) { y = this.maxY; }
22627         }
22628
22629         x = this.getTick(x, this.xTicks);
22630         y = this.getTick(y, this.yTicks);
22631
22632
22633         return {x:x, y:y};
22634     },
22635
22636     /*
22637      * Sets up config options specific to this class. Overrides
22638      * Roo.dd.DragDrop, but all versions of this method through the
22639      * inheritance chain are called
22640      */
22641     applyConfig: function() {
22642         Roo.dd.DD.superclass.applyConfig.call(this);
22643         this.scroll = (this.config.scroll !== false);
22644     },
22645
22646     /*
22647      * Event that fires prior to the onMouseDown event.  Overrides
22648      * Roo.dd.DragDrop.
22649      */
22650     b4MouseDown: function(e) {
22651         // this.resetConstraints();
22652         this.autoOffset(e.getPageX(),
22653                             e.getPageY());
22654     },
22655
22656     /*
22657      * Event that fires prior to the onDrag event.  Overrides
22658      * Roo.dd.DragDrop.
22659      */
22660     b4Drag: function(e) {
22661         this.setDragElPos(e.getPageX(),
22662                             e.getPageY());
22663     },
22664
22665     toString: function() {
22666         return ("DD " + this.id);
22667     }
22668
22669     //////////////////////////////////////////////////////////////////////////
22670     // Debugging ygDragDrop events that can be overridden
22671     //////////////////////////////////////////////////////////////////////////
22672     /*
22673     startDrag: function(x, y) {
22674     },
22675
22676     onDrag: function(e) {
22677     },
22678
22679     onDragEnter: function(e, id) {
22680     },
22681
22682     onDragOver: function(e, id) {
22683     },
22684
22685     onDragOut: function(e, id) {
22686     },
22687
22688     onDragDrop: function(e, id) {
22689     },
22690
22691     endDrag: function(e) {
22692     }
22693
22694     */
22695
22696 });/*
22697  * Based on:
22698  * Ext JS Library 1.1.1
22699  * Copyright(c) 2006-2007, Ext JS, LLC.
22700  *
22701  * Originally Released Under LGPL - original licence link has changed is not relivant.
22702  *
22703  * Fork - LGPL
22704  * <script type="text/javascript">
22705  */
22706
22707 /**
22708  * @class Roo.dd.DDProxy
22709  * A DragDrop implementation that inserts an empty, bordered div into
22710  * the document that follows the cursor during drag operations.  At the time of
22711  * the click, the frame div is resized to the dimensions of the linked html
22712  * element, and moved to the exact location of the linked element.
22713  *
22714  * References to the "frame" element refer to the single proxy element that
22715  * was created to be dragged in place of all DDProxy elements on the
22716  * page.
22717  *
22718  * @extends Roo.dd.DD
22719  * @constructor
22720  * @param {String} id the id of the linked html element
22721  * @param {String} sGroup the group of related DragDrop objects
22722  * @param {object} config an object containing configurable attributes
22723  *                Valid properties for DDProxy in addition to those in DragDrop:
22724  *                   resizeFrame, centerFrame, dragElId
22725  */
22726 Roo.dd.DDProxy = function(id, sGroup, config) {
22727     if (id) {
22728         this.init(id, sGroup, config);
22729         this.initFrame();
22730     }
22731 };
22732
22733 /**
22734  * The default drag frame div id
22735  * @property Roo.dd.DDProxy.dragElId
22736  * @type String
22737  * @static
22738  */
22739 Roo.dd.DDProxy.dragElId = "ygddfdiv";
22740
22741 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
22742
22743     /**
22744      * By default we resize the drag frame to be the same size as the element
22745      * we want to drag (this is to get the frame effect).  We can turn it off
22746      * if we want a different behavior.
22747      * @property resizeFrame
22748      * @type boolean
22749      */
22750     resizeFrame: true,
22751
22752     /**
22753      * By default the frame is positioned exactly where the drag element is, so
22754      * we use the cursor offset provided by Roo.dd.DD.  Another option that works only if
22755      * you do not have constraints on the obj is to have the drag frame centered
22756      * around the cursor.  Set centerFrame to true for this effect.
22757      * @property centerFrame
22758      * @type boolean
22759      */
22760     centerFrame: false,
22761
22762     /**
22763      * Creates the proxy element if it does not yet exist
22764      * @method createFrame
22765      */
22766     createFrame: function() {
22767         var self = this;
22768         var body = document.body;
22769
22770         if (!body || !body.firstChild) {
22771             setTimeout( function() { self.createFrame(); }, 50 );
22772             return;
22773         }
22774
22775         var div = this.getDragEl();
22776
22777         if (!div) {
22778             div    = document.createElement("div");
22779             div.id = this.dragElId;
22780             var s  = div.style;
22781
22782             s.position   = "absolute";
22783             s.visibility = "hidden";
22784             s.cursor     = "move";
22785             s.border     = "2px solid #aaa";
22786             s.zIndex     = 999;
22787
22788             // appendChild can blow up IE if invoked prior to the window load event
22789             // while rendering a table.  It is possible there are other scenarios
22790             // that would cause this to happen as well.
22791             body.insertBefore(div, body.firstChild);
22792         }
22793     },
22794
22795     /**
22796      * Initialization for the drag frame element.  Must be called in the
22797      * constructor of all subclasses
22798      * @method initFrame
22799      */
22800     initFrame: function() {
22801         this.createFrame();
22802     },
22803
22804     applyConfig: function() {
22805         Roo.dd.DDProxy.superclass.applyConfig.call(this);
22806
22807         this.resizeFrame = (this.config.resizeFrame !== false);
22808         this.centerFrame = (this.config.centerFrame);
22809         this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
22810     },
22811
22812     /**
22813      * Resizes the drag frame to the dimensions of the clicked object, positions
22814      * it over the object, and finally displays it
22815      * @method showFrame
22816      * @param {int} iPageX X click position
22817      * @param {int} iPageY Y click position
22818      * @private
22819      */
22820     showFrame: function(iPageX, iPageY) {
22821         var el = this.getEl();
22822         var dragEl = this.getDragEl();
22823         var s = dragEl.style;
22824
22825         this._resizeProxy();
22826
22827         if (this.centerFrame) {
22828             this.setDelta( Math.round(parseInt(s.width,  10)/2),
22829                            Math.round(parseInt(s.height, 10)/2) );
22830         }
22831
22832         this.setDragElPos(iPageX, iPageY);
22833
22834         Roo.fly(dragEl).show();
22835     },
22836
22837     /**
22838      * The proxy is automatically resized to the dimensions of the linked
22839      * element when a drag is initiated, unless resizeFrame is set to false
22840      * @method _resizeProxy
22841      * @private
22842      */
22843     _resizeProxy: function() {
22844         if (this.resizeFrame) {
22845             var el = this.getEl();
22846             Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
22847         }
22848     },
22849
22850     // overrides Roo.dd.DragDrop
22851     b4MouseDown: function(e) {
22852         var x = e.getPageX();
22853         var y = e.getPageY();
22854         this.autoOffset(x, y);
22855         this.setDragElPos(x, y);
22856     },
22857
22858     // overrides Roo.dd.DragDrop
22859     b4StartDrag: function(x, y) {
22860         // show the drag frame
22861         this.showFrame(x, y);
22862     },
22863
22864     // overrides Roo.dd.DragDrop
22865     b4EndDrag: function(e) {
22866         Roo.fly(this.getDragEl()).hide();
22867     },
22868
22869     // overrides Roo.dd.DragDrop
22870     // By default we try to move the element to the last location of the frame.
22871     // This is so that the default behavior mirrors that of Roo.dd.DD.
22872     endDrag: function(e) {
22873
22874         var lel = this.getEl();
22875         var del = this.getDragEl();
22876
22877         // Show the drag frame briefly so we can get its position
22878         del.style.visibility = "";
22879
22880         this.beforeMove();
22881         // Hide the linked element before the move to get around a Safari
22882         // rendering bug.
22883         lel.style.visibility = "hidden";
22884         Roo.dd.DDM.moveToEl(lel, del);
22885         del.style.visibility = "hidden";
22886         lel.style.visibility = "";
22887
22888         this.afterDrag();
22889     },
22890
22891     beforeMove : function(){
22892
22893     },
22894
22895     afterDrag : function(){
22896
22897     },
22898
22899     toString: function() {
22900         return ("DDProxy " + this.id);
22901     }
22902
22903 });
22904 /*
22905  * Based on:
22906  * Ext JS Library 1.1.1
22907  * Copyright(c) 2006-2007, Ext JS, LLC.
22908  *
22909  * Originally Released Under LGPL - original licence link has changed is not relivant.
22910  *
22911  * Fork - LGPL
22912  * <script type="text/javascript">
22913  */
22914
22915  /**
22916  * @class Roo.dd.DDTarget
22917  * A DragDrop implementation that does not move, but can be a drop
22918  * target.  You would get the same result by simply omitting implementation
22919  * for the event callbacks, but this way we reduce the processing cost of the
22920  * event listener and the callbacks.
22921  * @extends Roo.dd.DragDrop
22922  * @constructor
22923  * @param {String} id the id of the element that is a drop target
22924  * @param {String} sGroup the group of related DragDrop objects
22925  * @param {object} config an object containing configurable attributes
22926  *                 Valid properties for DDTarget in addition to those in
22927  *                 DragDrop:
22928  *                    none
22929  */
22930 Roo.dd.DDTarget = function(id, sGroup, config) {
22931     if (id) {
22932         this.initTarget(id, sGroup, config);
22933     }
22934     if (config && (config.listeners || config.events)) { 
22935         Roo.dd.DragDrop.superclass.constructor.call(this,  { 
22936             listeners : config.listeners || {}, 
22937             events : config.events || {} 
22938         });    
22939     }
22940 };
22941
22942 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
22943 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
22944     toString: function() {
22945         return ("DDTarget " + this.id);
22946     }
22947 });
22948 /*
22949  * Based on:
22950  * Ext JS Library 1.1.1
22951  * Copyright(c) 2006-2007, Ext JS, LLC.
22952  *
22953  * Originally Released Under LGPL - original licence link has changed is not relivant.
22954  *
22955  * Fork - LGPL
22956  * <script type="text/javascript">
22957  */
22958  
22959
22960 /**
22961  * @class Roo.dd.ScrollManager
22962  * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
22963  * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
22964  * @static
22965  */
22966 Roo.dd.ScrollManager = function(){
22967     var ddm = Roo.dd.DragDropMgr;
22968     var els = {};
22969     var dragEl = null;
22970     var proc = {};
22971     
22972     
22973     
22974     var onStop = function(e){
22975         dragEl = null;
22976         clearProc();
22977     };
22978     
22979     var triggerRefresh = function(){
22980         if(ddm.dragCurrent){
22981              ddm.refreshCache(ddm.dragCurrent.groups);
22982         }
22983     };
22984     
22985     var doScroll = function(){
22986         if(ddm.dragCurrent){
22987             var dds = Roo.dd.ScrollManager;
22988             if(!dds.animate){
22989                 if(proc.el.scroll(proc.dir, dds.increment)){
22990                     triggerRefresh();
22991                 }
22992             }else{
22993                 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
22994             }
22995         }
22996     };
22997     
22998     var clearProc = function(){
22999         if(proc.id){
23000             clearInterval(proc.id);
23001         }
23002         proc.id = 0;
23003         proc.el = null;
23004         proc.dir = "";
23005     };
23006     
23007     var startProc = function(el, dir){
23008          Roo.log('scroll startproc');
23009         clearProc();
23010         proc.el = el;
23011         proc.dir = dir;
23012         proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
23013     };
23014     
23015     var onFire = function(e, isDrop){
23016        
23017         if(isDrop || !ddm.dragCurrent){ return; }
23018         var dds = Roo.dd.ScrollManager;
23019         if(!dragEl || dragEl != ddm.dragCurrent){
23020             dragEl = ddm.dragCurrent;
23021             // refresh regions on drag start
23022             dds.refreshCache();
23023         }
23024         
23025         var xy = Roo.lib.Event.getXY(e);
23026         var pt = new Roo.lib.Point(xy[0], xy[1]);
23027         for(var id in els){
23028             var el = els[id], r = el._region;
23029             if(r && r.contains(pt) && el.isScrollable()){
23030                 if(r.bottom - pt.y <= dds.thresh){
23031                     if(proc.el != el){
23032                         startProc(el, "down");
23033                     }
23034                     return;
23035                 }else if(r.right - pt.x <= dds.thresh){
23036                     if(proc.el != el){
23037                         startProc(el, "left");
23038                     }
23039                     return;
23040                 }else if(pt.y - r.top <= dds.thresh){
23041                     if(proc.el != el){
23042                         startProc(el, "up");
23043                     }
23044                     return;
23045                 }else if(pt.x - r.left <= dds.thresh){
23046                     if(proc.el != el){
23047                         startProc(el, "right");
23048                     }
23049                     return;
23050                 }
23051             }
23052         }
23053         clearProc();
23054     };
23055     
23056     ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
23057     ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
23058     
23059     return {
23060         /**
23061          * Registers new overflow element(s) to auto scroll
23062          * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
23063          */
23064         register : function(el){
23065             if(el instanceof Array){
23066                 for(var i = 0, len = el.length; i < len; i++) {
23067                         this.register(el[i]);
23068                 }
23069             }else{
23070                 el = Roo.get(el);
23071                 els[el.id] = el;
23072             }
23073             Roo.dd.ScrollManager.els = els;
23074         },
23075         
23076         /**
23077          * Unregisters overflow element(s) so they are no longer scrolled
23078          * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
23079          */
23080         unregister : function(el){
23081             if(el instanceof Array){
23082                 for(var i = 0, len = el.length; i < len; i++) {
23083                         this.unregister(el[i]);
23084                 }
23085             }else{
23086                 el = Roo.get(el);
23087                 delete els[el.id];
23088             }
23089         },
23090         
23091         /**
23092          * The number of pixels from the edge of a container the pointer needs to be to 
23093          * trigger scrolling (defaults to 25)
23094          * @type Number
23095          */
23096         thresh : 25,
23097         
23098         /**
23099          * The number of pixels to scroll in each scroll increment (defaults to 50)
23100          * @type Number
23101          */
23102         increment : 100,
23103         
23104         /**
23105          * The frequency of scrolls in milliseconds (defaults to 500)
23106          * @type Number
23107          */
23108         frequency : 500,
23109         
23110         /**
23111          * True to animate the scroll (defaults to true)
23112          * @type Boolean
23113          */
23114         animate: true,
23115         
23116         /**
23117          * The animation duration in seconds - 
23118          * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
23119          * @type Number
23120          */
23121         animDuration: .4,
23122         
23123         /**
23124          * Manually trigger a cache refresh.
23125          */
23126         refreshCache : function(){
23127             for(var id in els){
23128                 if(typeof els[id] == 'object'){ // for people extending the object prototype
23129                     els[id]._region = els[id].getRegion();
23130                 }
23131             }
23132         }
23133     };
23134 }();/*
23135  * Based on:
23136  * Ext JS Library 1.1.1
23137  * Copyright(c) 2006-2007, Ext JS, LLC.
23138  *
23139  * Originally Released Under LGPL - original licence link has changed is not relivant.
23140  *
23141  * Fork - LGPL
23142  * <script type="text/javascript">
23143  */
23144  
23145
23146 /**
23147  * @class Roo.dd.Registry
23148  * Provides easy access to all drag drop components that are registered on a page.  Items can be retrieved either
23149  * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
23150  * @static
23151  */
23152 Roo.dd.Registry = function(){
23153     var elements = {}; 
23154     var handles = {}; 
23155     var autoIdSeed = 0;
23156
23157     var getId = function(el, autogen){
23158         if(typeof el == "string"){
23159             return el;
23160         }
23161         var id = el.id;
23162         if(!id && autogen !== false){
23163             id = "roodd-" + (++autoIdSeed);
23164             el.id = id;
23165         }
23166         return id;
23167     };
23168     
23169     return {
23170     /**
23171      * Register a drag drop element
23172      * @param {String|HTMLElement} element The id or DOM node to register
23173      * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
23174      * in drag drop operations.  You can populate this object with any arbitrary properties that your own code
23175      * knows how to interpret, plus there are some specific properties known to the Registry that should be
23176      * populated in the data object (if applicable):
23177      * <pre>
23178 Value      Description<br />
23179 ---------  ------------------------------------------<br />
23180 handles    Array of DOM nodes that trigger dragging<br />
23181            for the element being registered<br />
23182 isHandle   True if the element passed in triggers<br />
23183            dragging itself, else false
23184 </pre>
23185      */
23186         register : function(el, data){
23187             data = data || {};
23188             if(typeof el == "string"){
23189                 el = document.getElementById(el);
23190             }
23191             data.ddel = el;
23192             elements[getId(el)] = data;
23193             if(data.isHandle !== false){
23194                 handles[data.ddel.id] = data;
23195             }
23196             if(data.handles){
23197                 var hs = data.handles;
23198                 for(var i = 0, len = hs.length; i < len; i++){
23199                         handles[getId(hs[i])] = data;
23200                 }
23201             }
23202         },
23203
23204     /**
23205      * Unregister a drag drop element
23206      * @param {String|HTMLElement}  element The id or DOM node to unregister
23207      */
23208         unregister : function(el){
23209             var id = getId(el, false);
23210             var data = elements[id];
23211             if(data){
23212                 delete elements[id];
23213                 if(data.handles){
23214                     var hs = data.handles;
23215                     for(var i = 0, len = hs.length; i < len; i++){
23216                         delete handles[getId(hs[i], false)];
23217                     }
23218                 }
23219             }
23220         },
23221
23222     /**
23223      * Returns the handle registered for a DOM Node by id
23224      * @param {String|HTMLElement} id The DOM node or id to look up
23225      * @return {Object} handle The custom handle data
23226      */
23227         getHandle : function(id){
23228             if(typeof id != "string"){ // must be element?
23229                 id = id.id;
23230             }
23231             return handles[id];
23232         },
23233
23234     /**
23235      * Returns the handle that is registered for the DOM node that is the target of the event
23236      * @param {Event} e The event
23237      * @return {Object} handle The custom handle data
23238      */
23239         getHandleFromEvent : function(e){
23240             var t = Roo.lib.Event.getTarget(e);
23241             return t ? handles[t.id] : null;
23242         },
23243
23244     /**
23245      * Returns a custom data object that is registered for a DOM node by id
23246      * @param {String|HTMLElement} id The DOM node or id to look up
23247      * @return {Object} data The custom data
23248      */
23249         getTarget : function(id){
23250             if(typeof id != "string"){ // must be element?
23251                 id = id.id;
23252             }
23253             return elements[id];
23254         },
23255
23256     /**
23257      * Returns a custom data object that is registered for the DOM node that is the target of the event
23258      * @param {Event} e The event
23259      * @return {Object} data The custom data
23260      */
23261         getTargetFromEvent : function(e){
23262             var t = Roo.lib.Event.getTarget(e);
23263             return t ? elements[t.id] || handles[t.id] : null;
23264         }
23265     };
23266 }();/*
23267  * Based on:
23268  * Ext JS Library 1.1.1
23269  * Copyright(c) 2006-2007, Ext JS, LLC.
23270  *
23271  * Originally Released Under LGPL - original licence link has changed is not relivant.
23272  *
23273  * Fork - LGPL
23274  * <script type="text/javascript">
23275  */
23276  
23277
23278 /**
23279  * @class Roo.dd.StatusProxy
23280  * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair.  This is the
23281  * default drag proxy used by all Roo.dd components.
23282  * @constructor
23283  * @param {Object} config
23284  */
23285 Roo.dd.StatusProxy = function(config){
23286     Roo.apply(this, config);
23287     this.id = this.id || Roo.id();
23288     this.el = new Roo.Layer({
23289         dh: {
23290             id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
23291                 {tag: "div", cls: "x-dd-drop-icon"},
23292                 {tag: "div", cls: "x-dd-drag-ghost"}
23293             ]
23294         }, 
23295         shadow: !config || config.shadow !== false
23296     });
23297     this.ghost = Roo.get(this.el.dom.childNodes[1]);
23298     this.dropStatus = this.dropNotAllowed;
23299 };
23300
23301 Roo.dd.StatusProxy.prototype = {
23302     /**
23303      * @cfg {String} dropAllowed
23304      * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
23305      */
23306     dropAllowed : "x-dd-drop-ok",
23307     /**
23308      * @cfg {String} dropNotAllowed
23309      * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
23310      */
23311     dropNotAllowed : "x-dd-drop-nodrop",
23312
23313     /**
23314      * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
23315      * over the current target element.
23316      * @param {String} cssClass The css class for the new drop status indicator image
23317      */
23318     setStatus : function(cssClass){
23319         cssClass = cssClass || this.dropNotAllowed;
23320         if(this.dropStatus != cssClass){
23321             this.el.replaceClass(this.dropStatus, cssClass);
23322             this.dropStatus = cssClass;
23323         }
23324     },
23325
23326     /**
23327      * Resets the status indicator to the default dropNotAllowed value
23328      * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
23329      */
23330     reset : function(clearGhost){
23331         this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
23332         this.dropStatus = this.dropNotAllowed;
23333         if(clearGhost){
23334             this.ghost.update("");
23335         }
23336     },
23337
23338     /**
23339      * Updates the contents of the ghost element
23340      * @param {String} html The html that will replace the current innerHTML of the ghost element
23341      */
23342     update : function(html){
23343         if(typeof html == "string"){
23344             this.ghost.update(html);
23345         }else{
23346             this.ghost.update("");
23347             html.style.margin = "0";
23348             this.ghost.dom.appendChild(html);
23349         }
23350         // ensure float = none set?? cant remember why though.
23351         var el = this.ghost.dom.firstChild;
23352                 if(el){
23353                         Roo.fly(el).setStyle('float', 'none');
23354                 }
23355     },
23356     
23357     /**
23358      * Returns the underlying proxy {@link Roo.Layer}
23359      * @return {Roo.Layer} el
23360     */
23361     getEl : function(){
23362         return this.el;
23363     },
23364
23365     /**
23366      * Returns the ghost element
23367      * @return {Roo.Element} el
23368      */
23369     getGhost : function(){
23370         return this.ghost;
23371     },
23372
23373     /**
23374      * Hides the proxy
23375      * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
23376      */
23377     hide : function(clear){
23378         this.el.hide();
23379         if(clear){
23380             this.reset(true);
23381         }
23382     },
23383
23384     /**
23385      * Stops the repair animation if it's currently running
23386      */
23387     stop : function(){
23388         if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
23389             this.anim.stop();
23390         }
23391     },
23392
23393     /**
23394      * Displays this proxy
23395      */
23396     show : function(){
23397         this.el.show();
23398     },
23399
23400     /**
23401      * Force the Layer to sync its shadow and shim positions to the element
23402      */
23403     sync : function(){
23404         this.el.sync();
23405     },
23406
23407     /**
23408      * Causes the proxy to return to its position of origin via an animation.  Should be called after an
23409      * invalid drop operation by the item being dragged.
23410      * @param {Array} xy The XY position of the element ([x, y])
23411      * @param {Function} callback The function to call after the repair is complete
23412      * @param {Object} scope The scope in which to execute the callback
23413      */
23414     repair : function(xy, callback, scope){
23415         this.callback = callback;
23416         this.scope = scope;
23417         if(xy && this.animRepair !== false){
23418             this.el.addClass("x-dd-drag-repair");
23419             this.el.hideUnders(true);
23420             this.anim = this.el.shift({
23421                 duration: this.repairDuration || .5,
23422                 easing: 'easeOut',
23423                 xy: xy,
23424                 stopFx: true,
23425                 callback: this.afterRepair,
23426                 scope: this
23427             });
23428         }else{
23429             this.afterRepair();
23430         }
23431     },
23432
23433     // private
23434     afterRepair : function(){
23435         this.hide(true);
23436         if(typeof this.callback == "function"){
23437             this.callback.call(this.scope || this);
23438         }
23439         this.callback = null;
23440         this.scope = null;
23441     }
23442 };/*
23443  * Based on:
23444  * Ext JS Library 1.1.1
23445  * Copyright(c) 2006-2007, Ext JS, LLC.
23446  *
23447  * Originally Released Under LGPL - original licence link has changed is not relivant.
23448  *
23449  * Fork - LGPL
23450  * <script type="text/javascript">
23451  */
23452
23453 /**
23454  * @class Roo.dd.DragSource
23455  * @extends Roo.dd.DDProxy
23456  * A simple class that provides the basic implementation needed to make any element draggable.
23457  * @constructor
23458  * @param {String/HTMLElement/Element} el The container element
23459  * @param {Object} config
23460  */
23461 Roo.dd.DragSource = function(el, config){
23462     this.el = Roo.get(el);
23463     this.dragData = {};
23464     
23465     Roo.apply(this, config);
23466     
23467     if(!this.proxy){
23468         this.proxy = new Roo.dd.StatusProxy();
23469     }
23470
23471     Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
23472           {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
23473     
23474     this.dragging = false;
23475 };
23476
23477 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
23478     /**
23479      * @cfg {String} dropAllowed
23480      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
23481      */
23482     dropAllowed : "x-dd-drop-ok",
23483     /**
23484      * @cfg {String} dropNotAllowed
23485      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
23486      */
23487     dropNotAllowed : "x-dd-drop-nodrop",
23488
23489     /**
23490      * Returns the data object associated with this drag source
23491      * @return {Object} data An object containing arbitrary data
23492      */
23493     getDragData : function(e){
23494         return this.dragData;
23495     },
23496
23497     // private
23498     onDragEnter : function(e, id){
23499         var target = Roo.dd.DragDropMgr.getDDById(id);
23500         this.cachedTarget = target;
23501         if(this.beforeDragEnter(target, e, id) !== false){
23502             if(target.isNotifyTarget){
23503                 var status = target.notifyEnter(this, e, this.dragData);
23504                 this.proxy.setStatus(status);
23505             }else{
23506                 this.proxy.setStatus(this.dropAllowed);
23507             }
23508             
23509             if(this.afterDragEnter){
23510                 /**
23511                  * An empty function by default, but provided so that you can perform a custom action
23512                  * when the dragged item enters the drop target by providing an implementation.
23513                  * @param {Roo.dd.DragDrop} target The drop target
23514                  * @param {Event} e The event object
23515                  * @param {String} id The id of the dragged element
23516                  * @method afterDragEnter
23517                  */
23518                 this.afterDragEnter(target, e, id);
23519             }
23520         }
23521     },
23522
23523     /**
23524      * An empty function by default, but provided so that you can perform a custom action
23525      * before the dragged item enters the drop target and optionally cancel the onDragEnter.
23526      * @param {Roo.dd.DragDrop} target The drop target
23527      * @param {Event} e The event object
23528      * @param {String} id The id of the dragged element
23529      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23530      */
23531     beforeDragEnter : function(target, e, id){
23532         return true;
23533     },
23534
23535     // private
23536     alignElWithMouse: function() {
23537         Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
23538         this.proxy.sync();
23539     },
23540
23541     // private
23542     onDragOver : function(e, id){
23543         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23544         if(this.beforeDragOver(target, e, id) !== false){
23545             if(target.isNotifyTarget){
23546                 var status = target.notifyOver(this, e, this.dragData);
23547                 this.proxy.setStatus(status);
23548             }
23549
23550             if(this.afterDragOver){
23551                 /**
23552                  * An empty function by default, but provided so that you can perform a custom action
23553                  * while the dragged item is over the drop target by providing an implementation.
23554                  * @param {Roo.dd.DragDrop} target The drop target
23555                  * @param {Event} e The event object
23556                  * @param {String} id The id of the dragged element
23557                  * @method afterDragOver
23558                  */
23559                 this.afterDragOver(target, e, id);
23560             }
23561         }
23562     },
23563
23564     /**
23565      * An empty function by default, but provided so that you can perform a custom action
23566      * while the dragged item is over the drop target and optionally cancel the onDragOver.
23567      * @param {Roo.dd.DragDrop} target The drop target
23568      * @param {Event} e The event object
23569      * @param {String} id The id of the dragged element
23570      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23571      */
23572     beforeDragOver : function(target, e, id){
23573         return true;
23574     },
23575
23576     // private
23577     onDragOut : function(e, id){
23578         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23579         if(this.beforeDragOut(target, e, id) !== false){
23580             if(target.isNotifyTarget){
23581                 target.notifyOut(this, e, this.dragData);
23582             }
23583             this.proxy.reset();
23584             if(this.afterDragOut){
23585                 /**
23586                  * An empty function by default, but provided so that you can perform a custom action
23587                  * after the dragged item is dragged out of the target without dropping.
23588                  * @param {Roo.dd.DragDrop} target The drop target
23589                  * @param {Event} e The event object
23590                  * @param {String} id The id of the dragged element
23591                  * @method afterDragOut
23592                  */
23593                 this.afterDragOut(target, e, id);
23594             }
23595         }
23596         this.cachedTarget = null;
23597     },
23598
23599     /**
23600      * An empty function by default, but provided so that you can perform a custom action before the dragged
23601      * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
23602      * @param {Roo.dd.DragDrop} target The drop target
23603      * @param {Event} e The event object
23604      * @param {String} id The id of the dragged element
23605      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23606      */
23607     beforeDragOut : function(target, e, id){
23608         return true;
23609     },
23610     
23611     // private
23612     onDragDrop : function(e, id){
23613         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23614         if(this.beforeDragDrop(target, e, id) !== false){
23615             if(target.isNotifyTarget){
23616                 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
23617                     this.onValidDrop(target, e, id);
23618                 }else{
23619                     this.onInvalidDrop(target, e, id);
23620                 }
23621             }else{
23622                 this.onValidDrop(target, e, id);
23623             }
23624             
23625             if(this.afterDragDrop){
23626                 /**
23627                  * An empty function by default, but provided so that you can perform a custom action
23628                  * after a valid drag drop has occurred by providing an implementation.
23629                  * @param {Roo.dd.DragDrop} target The drop target
23630                  * @param {Event} e The event object
23631                  * @param {String} id The id of the dropped element
23632                  * @method afterDragDrop
23633                  */
23634                 this.afterDragDrop(target, e, id);
23635             }
23636         }
23637         delete this.cachedTarget;
23638     },
23639
23640     /**
23641      * An empty function by default, but provided so that you can perform a custom action before the dragged
23642      * item is dropped onto the target and optionally cancel the onDragDrop.
23643      * @param {Roo.dd.DragDrop} target The drop target
23644      * @param {Event} e The event object
23645      * @param {String} id The id of the dragged element
23646      * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
23647      */
23648     beforeDragDrop : function(target, e, id){
23649         return true;
23650     },
23651
23652     // private
23653     onValidDrop : function(target, e, id){
23654         this.hideProxy();
23655         if(this.afterValidDrop){
23656             /**
23657              * An empty function by default, but provided so that you can perform a custom action
23658              * after a valid drop has occurred by providing an implementation.
23659              * @param {Object} target The target DD 
23660              * @param {Event} e The event object
23661              * @param {String} id The id of the dropped element
23662              * @method afterInvalidDrop
23663              */
23664             this.afterValidDrop(target, e, id);
23665         }
23666     },
23667
23668     // private
23669     getRepairXY : function(e, data){
23670         return this.el.getXY();  
23671     },
23672
23673     // private
23674     onInvalidDrop : function(target, e, id){
23675         this.beforeInvalidDrop(target, e, id);
23676         if(this.cachedTarget){
23677             if(this.cachedTarget.isNotifyTarget){
23678                 this.cachedTarget.notifyOut(this, e, this.dragData);
23679             }
23680             this.cacheTarget = null;
23681         }
23682         this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
23683
23684         if(this.afterInvalidDrop){
23685             /**
23686              * An empty function by default, but provided so that you can perform a custom action
23687              * after an invalid drop has occurred by providing an implementation.
23688              * @param {Event} e The event object
23689              * @param {String} id The id of the dropped element
23690              * @method afterInvalidDrop
23691              */
23692             this.afterInvalidDrop(e, id);
23693         }
23694     },
23695
23696     // private
23697     afterRepair : function(){
23698         if(Roo.enableFx){
23699             this.el.highlight(this.hlColor || "c3daf9");
23700         }
23701         this.dragging = false;
23702     },
23703
23704     /**
23705      * An empty function by default, but provided so that you can perform a custom action after an invalid
23706      * drop has occurred.
23707      * @param {Roo.dd.DragDrop} target The drop target
23708      * @param {Event} e The event object
23709      * @param {String} id The id of the dragged element
23710      * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
23711      */
23712     beforeInvalidDrop : function(target, e, id){
23713         return true;
23714     },
23715
23716     // private
23717     handleMouseDown : function(e){
23718         if(this.dragging) {
23719             return;
23720         }
23721         var data = this.getDragData(e);
23722         if(data && this.onBeforeDrag(data, e) !== false){
23723             this.dragData = data;
23724             this.proxy.stop();
23725             Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
23726         } 
23727     },
23728
23729     /**
23730      * An empty function by default, but provided so that you can perform a custom action before the initial
23731      * drag event begins and optionally cancel it.
23732      * @param {Object} data An object containing arbitrary data to be shared with drop targets
23733      * @param {Event} e The event object
23734      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23735      */
23736     onBeforeDrag : function(data, e){
23737         return true;
23738     },
23739
23740     /**
23741      * An empty function by default, but provided so that you can perform a custom action once the initial
23742      * drag event has begun.  The drag cannot be canceled from this function.
23743      * @param {Number} x The x position of the click on the dragged object
23744      * @param {Number} y The y position of the click on the dragged object
23745      */
23746     onStartDrag : Roo.emptyFn,
23747
23748     // private - YUI override
23749     startDrag : function(x, y){
23750         this.proxy.reset();
23751         this.dragging = true;
23752         this.proxy.update("");
23753         this.onInitDrag(x, y);
23754         this.proxy.show();
23755     },
23756
23757     // private
23758     onInitDrag : function(x, y){
23759         var clone = this.el.dom.cloneNode(true);
23760         clone.id = Roo.id(); // prevent duplicate ids
23761         this.proxy.update(clone);
23762         this.onStartDrag(x, y);
23763         return true;
23764     },
23765
23766     /**
23767      * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
23768      * @return {Roo.dd.StatusProxy} proxy The StatusProxy
23769      */
23770     getProxy : function(){
23771         return this.proxy;  
23772     },
23773
23774     /**
23775      * Hides the drag source's {@link Roo.dd.StatusProxy}
23776      */
23777     hideProxy : function(){
23778         this.proxy.hide();  
23779         this.proxy.reset(true);
23780         this.dragging = false;
23781     },
23782
23783     // private
23784     triggerCacheRefresh : function(){
23785         Roo.dd.DDM.refreshCache(this.groups);
23786     },
23787
23788     // private - override to prevent hiding
23789     b4EndDrag: function(e) {
23790     },
23791
23792     // private - override to prevent moving
23793     endDrag : function(e){
23794         this.onEndDrag(this.dragData, e);
23795     },
23796
23797     // private
23798     onEndDrag : function(data, e){
23799     },
23800     
23801     // private - pin to cursor
23802     autoOffset : function(x, y) {
23803         this.setDelta(-12, -20);
23804     }    
23805 });/*
23806  * Based on:
23807  * Ext JS Library 1.1.1
23808  * Copyright(c) 2006-2007, Ext JS, LLC.
23809  *
23810  * Originally Released Under LGPL - original licence link has changed is not relivant.
23811  *
23812  * Fork - LGPL
23813  * <script type="text/javascript">
23814  */
23815
23816
23817 /**
23818  * @class Roo.dd.DropTarget
23819  * @extends Roo.dd.DDTarget
23820  * A simple class that provides the basic implementation needed to make any element a drop target that can have
23821  * draggable items dropped onto it.  The drop has no effect until an implementation of notifyDrop is provided.
23822  * @constructor
23823  * @param {String/HTMLElement/Element} el The container element
23824  * @param {Object} config
23825  */
23826 Roo.dd.DropTarget = function(el, config){
23827     this.el = Roo.get(el);
23828     
23829     var listeners = false; ;
23830     if (config && config.listeners) {
23831         listeners= config.listeners;
23832         delete config.listeners;
23833     }
23834     Roo.apply(this, config);
23835     
23836     if(this.containerScroll){
23837         Roo.dd.ScrollManager.register(this.el);
23838     }
23839     this.addEvents( {
23840          /**
23841          * @scope Roo.dd.DropTarget
23842          */
23843          
23844          /**
23845          * @event enter
23846          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
23847          * target.  This default implementation adds the CSS class specified by overClass (if any) to the drop element
23848          * and returns the dropAllowed config value.  This method should be overridden if drop validation is required.
23849          * 
23850          * IMPORTANT : it should set  this.valid to true|false
23851          * 
23852          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23853          * @param {Event} e The event
23854          * @param {Object} data An object containing arbitrary data supplied by the drag source
23855          */
23856         "enter" : true,
23857         
23858          /**
23859          * @event over
23860          * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
23861          * This method will be called on every mouse movement while the drag source is over the drop target.
23862          * This default implementation simply returns the dropAllowed config value.
23863          * 
23864          * IMPORTANT : it should set  this.valid to true|false
23865          * 
23866          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23867          * @param {Event} e The event
23868          * @param {Object} data An object containing arbitrary data supplied by the drag source
23869          
23870          */
23871         "over" : true,
23872         /**
23873          * @event out
23874          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
23875          * out of the target without dropping.  This default implementation simply removes the CSS class specified by
23876          * overClass (if any) from the drop element.
23877          * 
23878          * 
23879          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23880          * @param {Event} e The event
23881          * @param {Object} data An object containing arbitrary data supplied by the drag source
23882          */
23883          "out" : true,
23884          
23885         /**
23886          * @event drop
23887          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
23888          * been dropped on it.  This method has no default implementation and returns false, so you must provide an
23889          * implementation that does something to process the drop event and returns true so that the drag source's
23890          * repair action does not run.
23891          * 
23892          * IMPORTANT : it should set this.success
23893          * 
23894          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23895          * @param {Event} e The event
23896          * @param {Object} data An object containing arbitrary data supplied by the drag source
23897         */
23898          "drop" : true
23899     });
23900             
23901      
23902     Roo.dd.DropTarget.superclass.constructor.call(  this, 
23903         this.el.dom, 
23904         this.ddGroup || this.group,
23905         {
23906             isTarget: true,
23907             listeners : listeners || {} 
23908            
23909         
23910         }
23911     );
23912
23913 };
23914
23915 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
23916     /**
23917      * @cfg {String} overClass
23918      * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
23919      */
23920      /**
23921      * @cfg {String} ddGroup
23922      * The drag drop group to handle drop events for
23923      */
23924      
23925     /**
23926      * @cfg {String} dropAllowed
23927      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
23928      */
23929     dropAllowed : "x-dd-drop-ok",
23930     /**
23931      * @cfg {String} dropNotAllowed
23932      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
23933      */
23934     dropNotAllowed : "x-dd-drop-nodrop",
23935     /**
23936      * @cfg {boolean} success
23937      * set this after drop listener.. 
23938      */
23939     success : false,
23940     /**
23941      * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
23942      * if the drop point is valid for over/enter..
23943      */
23944     valid : false,
23945     // private
23946     isTarget : true,
23947
23948     // private
23949     isNotifyTarget : true,
23950     
23951     /**
23952      * @hide
23953      */
23954     notifyEnter : function(dd, e, data)
23955     {
23956         this.valid = true;
23957         this.fireEvent('enter', dd, e, data);
23958         if(this.overClass){
23959             this.el.addClass(this.overClass);
23960         }
23961         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
23962             this.valid ? this.dropAllowed : this.dropNotAllowed
23963         );
23964     },
23965
23966     /**
23967      * @hide
23968      */
23969     notifyOver : function(dd, e, data)
23970     {
23971         this.valid = true;
23972         this.fireEvent('over', dd, e, data);
23973         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
23974             this.valid ? this.dropAllowed : this.dropNotAllowed
23975         );
23976     },
23977
23978     /**
23979      * @hide
23980      */
23981     notifyOut : function(dd, e, data)
23982     {
23983         this.fireEvent('out', dd, e, data);
23984         if(this.overClass){
23985             this.el.removeClass(this.overClass);
23986         }
23987     },
23988
23989     /**
23990      * @hide
23991      */
23992     notifyDrop : function(dd, e, data)
23993     {
23994         this.success = false;
23995         this.fireEvent('drop', dd, e, data);
23996         return this.success;
23997     }
23998 });/*
23999  * Based on:
24000  * Ext JS Library 1.1.1
24001  * Copyright(c) 2006-2007, Ext JS, LLC.
24002  *
24003  * Originally Released Under LGPL - original licence link has changed is not relivant.
24004  *
24005  * Fork - LGPL
24006  * <script type="text/javascript">
24007  */
24008
24009
24010 /**
24011  * @class Roo.dd.DragZone
24012  * @extends Roo.dd.DragSource
24013  * This class provides a container DD instance that proxies for multiple child node sources.<br />
24014  * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
24015  * @constructor
24016  * @param {String/HTMLElement/Element} el The container element
24017  * @param {Object} config
24018  */
24019 Roo.dd.DragZone = function(el, config){
24020     Roo.dd.DragZone.superclass.constructor.call(this, el, config);
24021     if(this.containerScroll){
24022         Roo.dd.ScrollManager.register(this.el);
24023     }
24024 };
24025
24026 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
24027     /**
24028      * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
24029      * for auto scrolling during drag operations.
24030      */
24031     /**
24032      * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
24033      * method after a failed drop (defaults to "c3daf9" - light blue)
24034      */
24035
24036     /**
24037      * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
24038      * for a valid target to drag based on the mouse down. Override this method
24039      * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
24040      * object has a "ddel" attribute (with an HTML Element) for other functions to work.
24041      * @param {EventObject} e The mouse down event
24042      * @return {Object} The dragData
24043      */
24044     getDragData : function(e){
24045         return Roo.dd.Registry.getHandleFromEvent(e);
24046     },
24047     
24048     /**
24049      * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
24050      * this.dragData.ddel
24051      * @param {Number} x The x position of the click on the dragged object
24052      * @param {Number} y The y position of the click on the dragged object
24053      * @return {Boolean} true to continue the drag, false to cancel
24054      */
24055     onInitDrag : function(x, y){
24056         this.proxy.update(this.dragData.ddel.cloneNode(true));
24057         this.onStartDrag(x, y);
24058         return true;
24059     },
24060     
24061     /**
24062      * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel 
24063      */
24064     afterRepair : function(){
24065         if(Roo.enableFx){
24066             Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
24067         }
24068         this.dragging = false;
24069     },
24070
24071     /**
24072      * Called before a repair of an invalid drop to get the XY to animate to. By default returns
24073      * the XY of this.dragData.ddel
24074      * @param {EventObject} e The mouse up event
24075      * @return {Array} The xy location (e.g. [100, 200])
24076      */
24077     getRepairXY : function(e){
24078         return Roo.Element.fly(this.dragData.ddel).getXY();  
24079     }
24080 });/*
24081  * Based on:
24082  * Ext JS Library 1.1.1
24083  * Copyright(c) 2006-2007, Ext JS, LLC.
24084  *
24085  * Originally Released Under LGPL - original licence link has changed is not relivant.
24086  *
24087  * Fork - LGPL
24088  * <script type="text/javascript">
24089  */
24090 /**
24091  * @class Roo.dd.DropZone
24092  * @extends Roo.dd.DropTarget
24093  * This class provides a container DD instance that proxies for multiple child node targets.<br />
24094  * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
24095  * @constructor
24096  * @param {String/HTMLElement/Element} el The container element
24097  * @param {Object} config
24098  */
24099 Roo.dd.DropZone = function(el, config){
24100     Roo.dd.DropZone.superclass.constructor.call(this, el, config);
24101 };
24102
24103 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
24104     /**
24105      * Returns a custom data object associated with the DOM node that is the target of the event.  By default
24106      * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
24107      * provide your own custom lookup.
24108      * @param {Event} e The event
24109      * @return {Object} data The custom data
24110      */
24111     getTargetFromEvent : function(e){
24112         return Roo.dd.Registry.getTargetFromEvent(e);
24113     },
24114
24115     /**
24116      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
24117      * that it has registered.  This method has no default implementation and should be overridden to provide
24118      * node-specific processing if necessary.
24119      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from 
24120      * {@link #getTargetFromEvent} for this node)
24121      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24122      * @param {Event} e The event
24123      * @param {Object} data An object containing arbitrary data supplied by the drag source
24124      */
24125     onNodeEnter : function(n, dd, e, data){
24126         
24127     },
24128
24129     /**
24130      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
24131      * that it has registered.  The default implementation returns this.dropNotAllowed, so it should be
24132      * overridden to provide the proper feedback.
24133      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
24134      * {@link #getTargetFromEvent} for this node)
24135      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24136      * @param {Event} e The event
24137      * @param {Object} data An object containing arbitrary data supplied by the drag source
24138      * @return {String} status The CSS class that communicates the drop status back to the source so that the
24139      * underlying {@link Roo.dd.StatusProxy} can be updated
24140      */
24141     onNodeOver : function(n, dd, e, data){
24142         return this.dropAllowed;
24143     },
24144
24145     /**
24146      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
24147      * the drop node without dropping.  This method has no default implementation and should be overridden to provide
24148      * node-specific processing if necessary.
24149      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
24150      * {@link #getTargetFromEvent} for this node)
24151      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24152      * @param {Event} e The event
24153      * @param {Object} data An object containing arbitrary data supplied by the drag source
24154      */
24155     onNodeOut : function(n, dd, e, data){
24156         
24157     },
24158
24159     /**
24160      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
24161      * the drop node.  The default implementation returns false, so it should be overridden to provide the
24162      * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
24163      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
24164      * {@link #getTargetFromEvent} for this node)
24165      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24166      * @param {Event} e The event
24167      * @param {Object} data An object containing arbitrary data supplied by the drag source
24168      * @return {Boolean} True if the drop was valid, else false
24169      */
24170     onNodeDrop : function(n, dd, e, data){
24171         return false;
24172     },
24173
24174     /**
24175      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
24176      * but not over any of its registered drop nodes.  The default implementation returns this.dropNotAllowed, so
24177      * it should be overridden to provide the proper feedback if necessary.
24178      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24179      * @param {Event} e The event
24180      * @param {Object} data An object containing arbitrary data supplied by the drag source
24181      * @return {String} status The CSS class that communicates the drop status back to the source so that the
24182      * underlying {@link Roo.dd.StatusProxy} can be updated
24183      */
24184     onContainerOver : function(dd, e, data){
24185         return this.dropNotAllowed;
24186     },
24187
24188     /**
24189      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
24190      * but not on any of its registered drop nodes.  The default implementation returns false, so it should be
24191      * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
24192      * be able to accept drops.  It should return true when valid so that the drag source's repair action does not run.
24193      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24194      * @param {Event} e The event
24195      * @param {Object} data An object containing arbitrary data supplied by the drag source
24196      * @return {Boolean} True if the drop was valid, else false
24197      */
24198     onContainerDrop : function(dd, e, data){
24199         return false;
24200     },
24201
24202     /**
24203      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
24204      * the zone.  The default implementation returns this.dropNotAllowed and expects that only registered drop
24205      * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
24206      * you should override this method and provide a custom implementation.
24207      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24208      * @param {Event} e The event
24209      * @param {Object} data An object containing arbitrary data supplied by the drag source
24210      * @return {String} status The CSS class that communicates the drop status back to the source so that the
24211      * underlying {@link Roo.dd.StatusProxy} can be updated
24212      */
24213     notifyEnter : function(dd, e, data){
24214         return this.dropNotAllowed;
24215     },
24216
24217     /**
24218      * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
24219      * This method will be called on every mouse movement while the drag source is over the drop zone.
24220      * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
24221      * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
24222      * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
24223      * registered node, it will call {@link #onContainerOver}.
24224      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24225      * @param {Event} e The event
24226      * @param {Object} data An object containing arbitrary data supplied by the drag source
24227      * @return {String} status The CSS class that communicates the drop status back to the source so that the
24228      * underlying {@link Roo.dd.StatusProxy} can be updated
24229      */
24230     notifyOver : function(dd, e, data){
24231         var n = this.getTargetFromEvent(e);
24232         if(!n){ // not over valid drop target
24233             if(this.lastOverNode){
24234                 this.onNodeOut(this.lastOverNode, dd, e, data);
24235                 this.lastOverNode = null;
24236             }
24237             return this.onContainerOver(dd, e, data);
24238         }
24239         if(this.lastOverNode != n){
24240             if(this.lastOverNode){
24241                 this.onNodeOut(this.lastOverNode, dd, e, data);
24242             }
24243             this.onNodeEnter(n, dd, e, data);
24244             this.lastOverNode = n;
24245         }
24246         return this.onNodeOver(n, dd, e, data);
24247     },
24248
24249     /**
24250      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
24251      * out of the zone without dropping.  If the drag source is currently over a registered node, the notification
24252      * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
24253      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
24254      * @param {Event} e The event
24255      * @param {Object} data An object containing arbitrary data supplied by the drag zone
24256      */
24257     notifyOut : function(dd, e, data){
24258         if(this.lastOverNode){
24259             this.onNodeOut(this.lastOverNode, dd, e, data);
24260             this.lastOverNode = null;
24261         }
24262     },
24263
24264     /**
24265      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
24266      * been dropped on it.  The drag zone will look up the target node based on the event passed in, and if there
24267      * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
24268      * otherwise it will call {@link #onContainerDrop}.
24269      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24270      * @param {Event} e The event
24271      * @param {Object} data An object containing arbitrary data supplied by the drag source
24272      * @return {Boolean} True if the drop was valid, else false
24273      */
24274     notifyDrop : function(dd, e, data){
24275         if(this.lastOverNode){
24276             this.onNodeOut(this.lastOverNode, dd, e, data);
24277             this.lastOverNode = null;
24278         }
24279         var n = this.getTargetFromEvent(e);
24280         return n ?
24281             this.onNodeDrop(n, dd, e, data) :
24282             this.onContainerDrop(dd, e, data);
24283     },
24284
24285     // private
24286     triggerCacheRefresh : function(){
24287         Roo.dd.DDM.refreshCache(this.groups);
24288     }  
24289 });