sync
[roojs1] / roojs-core-debug.js
1 /*
2  * Based on:
3  * Ext JS Library 1.1.1
4  * Copyright(c) 2006-2007, Ext JS, LLC.
5  *
6  * Originally Released Under LGPL - original licence link has changed is not relivant.
7  *
8  * Fork - LGPL
9  * <script type="text/javascript">
10  */
11  
12
13
14
15
16 // for old browsers
17 window["undefined"] = window["undefined"];
18
19 /**
20  * @class Roo
21  * Roo core utilities and functions.
22  * @static
23  */
24 var Roo = {}; 
25 /**
26  * Copies all the properties of config to obj.
27  * @param {Object} obj The receiver of the properties
28  * @param {Object} config The source of the properties
29  * @param {Object} defaults A different object that will also be applied for default values
30  * @return {Object} returns obj
31  * @member Roo apply
32  */
33
34  
35 Roo.apply = function(o, c, defaults){
36     if(defaults){
37         // no "this" reference for friendly out of scope calls
38         Roo.apply(o, defaults);
39     }
40     if(o && c && typeof c == 'object'){
41         for(var p in c){
42             o[p] = c[p];
43         }
44     }
45     return o;
46 };
47
48
49 (function(){
50     var idSeed = 0;
51     var ua = navigator.userAgent.toLowerCase();
52
53     var isStrict = document.compatMode == "CSS1Compat",
54         isOpera = ua.indexOf("opera") > -1,
55         isSafari = (/webkit|khtml/).test(ua),
56         isFirefox = ua.indexOf("firefox") > -1,
57         isIE = ua.indexOf("msie") > -1,
58         isIE7 = ua.indexOf("msie 7") > -1,
59         isIE11 = /trident.*rv\:11\./.test(ua),
60         isEdge = ua.indexOf("edge") > -1,
61         isGecko = !isSafari && ua.indexOf("gecko") > -1,
62         isBorderBox = isIE && !isStrict,
63         isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
64         isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
65         isLinux = (ua.indexOf("linux") != -1),
66         isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
67         isIOS = /iphone|ipad/.test(ua),
68         isAndroid = /android/.test(ua),
69         isTouch =  (function() {
70             try {
71                 if (ua.indexOf('chrome') != -1 && ua.indexOf('android') == -1) {
72                     window.addEventListener('touchstart', function __set_has_touch__ () {
73                         Roo.isTouch = true;
74                         window.removeEventListener('touchstart', __set_has_touch__);
75                     });
76                     return false; // no touch on chrome!?
77                 }
78                 document.createEvent("TouchEvent");  
79                 return true;  
80             } catch (e) {  
81                 return false;  
82             } 
83             
84         })();
85     // remove css image flicker
86         if(isIE && !isIE7){
87         try{
88             document.execCommand("BackgroundImageCache", false, true);
89         }catch(e){}
90     }
91     
92     Roo.apply(Roo, {
93         /**
94          * True if the browser is in strict mode
95          * @type Boolean
96          */
97         isStrict : isStrict,
98         /**
99          * True if the page is running over SSL
100          * @type Boolean
101          */
102         isSecure : isSecure,
103         /**
104          * True when the document is fully initialized and ready for action
105          * @type Boolean
106          */
107         isReady : false,
108         /**
109          * Turn on debugging output (currently only the factory uses this)
110          * @type Boolean
111          */
112         
113         debug: false,
114
115         /**
116          * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
117          * @type Boolean
118          */
119         enableGarbageCollector : true,
120
121         /**
122          * True to automatically purge event listeners after uncaching an element (defaults to false).
123          * Note: this only happens if enableGarbageCollector is true.
124          * @type Boolean
125          */
126         enableListenerCollection:false,
127
128         /**
129          * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
130          * the IE insecure content warning (defaults to javascript:false).
131          * @type String
132          */
133         SSL_SECURE_URL : "javascript:false",
134
135         /**
136          * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
137          * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
138          * @type String
139          */
140         BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
141
142         emptyFn : function(){},
143         
144         /**
145          * Copies all the properties of config to obj if they don't already exist.
146          * @param {Object} obj The receiver of the properties
147          * @param {Object} config The source of the properties
148          * @return {Object} returns obj
149          */
150         applyIf : function(o, c){
151             if(o && c){
152                 for(var p in c){
153                     if(typeof o[p] == "undefined"){ o[p] = c[p]; }
154                 }
155             }
156             return o;
157         },
158
159         /**
160          * Applies event listeners to elements by selectors when the document is ready.
161          * The event name is specified with an @ suffix.
162 <pre><code>
163 Roo.addBehaviors({
164    // add a listener for click on all anchors in element with id foo
165    '#foo a@click' : function(e, t){
166        // do something
167    },
168
169    // add the same listener to multiple selectors (separated by comma BEFORE the @)
170    '#foo a, #bar span.some-class@mouseover' : function(){
171        // do something
172    }
173 });
174 </code></pre>
175          * @param {Object} obj The list of behaviors to apply
176          */
177         addBehaviors : function(o){
178             if(!Roo.isReady){
179                 Roo.onReady(function(){
180                     Roo.addBehaviors(o);
181                 });
182                 return;
183             }
184             var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
185             for(var b in o){
186                 var parts = b.split('@');
187                 if(parts[1]){ // for Object prototype breakers
188                     var s = parts[0];
189                     if(!cache[s]){
190                         cache[s] = Roo.select(s);
191                     }
192                     cache[s].on(parts[1], o[b]);
193                 }
194             }
195             cache = null;
196         },
197
198         /**
199          * Generates unique ids. If the element already has an id, it is unchanged
200          * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
201          * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
202          * @return {String} The generated Id.
203          */
204         id : function(el, prefix){
205             prefix = prefix || "roo-gen";
206             el = Roo.getDom(el);
207             var id = prefix + (++idSeed);
208             return el ? (el.id ? el.id : (el.id = id)) : id;
209         },
210          
211        
212         /**
213          * Extends one class with another class and optionally overrides members with the passed literal. This class
214          * also adds the function "override()" to the class that can be used to override
215          * members on an instance.
216          * @param {Object} subclass The class inheriting the functionality
217          * @param {Object} superclass The class being extended
218          * @param {Object} overrides (optional) A literal with members
219          * @method extend
220          */
221         extend : function(){
222             // inline overrides
223             var io = function(o){
224                 for(var m in o){
225                     this[m] = o[m];
226                 }
227             };
228             return function(sb, sp, overrides){
229                 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
230                     overrides = sp;
231                     sp = sb;
232                     sb = function(){sp.apply(this, arguments);};
233                 }
234                 var F = function(){}, sbp, spp = sp.prototype;
235                 F.prototype = spp;
236                 sbp = sb.prototype = new F();
237                 sbp.constructor=sb;
238                 sb.superclass=spp;
239                 
240                 if(spp.constructor == Object.prototype.constructor){
241                     spp.constructor=sp;
242                    
243                 }
244                 
245                 sb.override = function(o){
246                     Roo.override(sb, o);
247                 };
248                 sbp.override = io;
249                 Roo.override(sb, overrides);
250                 return sb;
251             };
252         }(),
253
254         /**
255          * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
256          * Usage:<pre><code>
257 Roo.override(MyClass, {
258     newMethod1: function(){
259         // etc.
260     },
261     newMethod2: function(foo){
262         // etc.
263     }
264 });
265  </code></pre>
266          * @param {Object} origclass The class to override
267          * @param {Object} overrides The list of functions to add to origClass.  This should be specified as an object literal
268          * containing one or more methods.
269          * @method override
270          */
271         override : function(origclass, overrides){
272             if(overrides){
273                 var p = origclass.prototype;
274                 for(var method in overrides){
275                     p[method] = overrides[method];
276                 }
277             }
278         },
279         /**
280          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
281          * <pre><code>
282 Roo.namespace('Company', 'Company.data');
283 Company.Widget = function() { ... }
284 Company.data.CustomStore = function(config) { ... }
285 </code></pre>
286          * @param {String} namespace1
287          * @param {String} namespace2
288          * @param {String} etc
289          * @method namespace
290          */
291         namespace : function(){
292             var a=arguments, o=null, i, j, d, rt;
293             for (i=0; i<a.length; ++i) {
294                 d=a[i].split(".");
295                 rt = d[0];
296                 /** eval:var:o */
297                 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
298                 for (j=1; j<d.length; ++j) {
299                     o[d[j]]=o[d[j]] || {};
300                     o=o[d[j]];
301                 }
302             }
303         },
304         /**
305          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
306          * <pre><code>
307 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
308 Roo.factory(conf, Roo.data);
309 </code></pre>
310          * @param {String} classname
311          * @param {String} namespace (optional)
312          * @method factory
313          */
314          
315         factory : function(c, ns)
316         {
317             // no xtype, no ns or c.xns - or forced off by c.xns
318             if (!c.xtype   || (!ns && !c.xns) ||  (c.xns === false)) { // not enough info...
319                 return c;
320             }
321             ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
322             if (c.constructor == ns[c.xtype]) {// already created...
323                 return c;
324             }
325             if (ns[c.xtype]) {
326                 if (Roo.debug) { Roo.log("Roo.Factory(" + c.xtype + ")"); }
327                 var ret = new ns[c.xtype](c);
328                 ret.xns = false;
329                 return ret;
330             }
331             c.xns = false; // prevent recursion..
332             return c;
333         },
334          /**
335          * Logs to console if it can.
336          *
337          * @param {String|Object} string
338          * @method log
339          */
340         log : function(s)
341         {
342             if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
343                 return; // alerT?
344             }
345             
346             console.log(s);
347         },
348         /**
349          * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2".  Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
350          * @param {Object} o
351          * @return {String}
352          */
353         urlEncode : function(o){
354             if(!o){
355                 return "";
356             }
357             var buf = [];
358             for(var key in o){
359                 var ov = o[key], k = Roo.encodeURIComponent(key);
360                 var type = typeof ov;
361                 if(type == 'undefined'){
362                     buf.push(k, "=&");
363                 }else if(type != "function" && type != "object"){
364                     buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
365                 }else if(ov instanceof Array){
366                     if (ov.length) {
367                             for(var i = 0, len = ov.length; i < len; i++) {
368                                 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
369                             }
370                         } else {
371                             buf.push(k, "=&");
372                         }
373                 }
374             }
375             buf.pop();
376             return buf.join("");
377         },
378          /**
379          * Safe version of encodeURIComponent
380          * @param {String} data 
381          * @return {String} 
382          */
383         
384         encodeURIComponent : function (data)
385         {
386             try {
387                 return encodeURIComponent(data);
388             } catch(e) {} // should be an uri encode error.
389             
390             if (data == '' || data == null){
391                return '';
392             }
393             // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
394             function nibble_to_hex(nibble){
395                 var chars = '0123456789ABCDEF';
396                 return chars.charAt(nibble);
397             }
398             data = data.toString();
399             var buffer = '';
400             for(var i=0; i<data.length; i++){
401                 var c = data.charCodeAt(i);
402                 var bs = new Array();
403                 if (c > 0x10000){
404                         // 4 bytes
405                     bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
406                     bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
407                     bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
408                     bs[3] = 0x80 | (c & 0x3F);
409                 }else if (c > 0x800){
410                          // 3 bytes
411                     bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
412                     bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
413                     bs[2] = 0x80 | (c & 0x3F);
414                 }else if (c > 0x80){
415                        // 2 bytes
416                     bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
417                     bs[1] = 0x80 | (c & 0x3F);
418                 }else{
419                         // 1 byte
420                     bs[0] = c;
421                 }
422                 for(var j=0; j<bs.length; j++){
423                     var b = bs[j];
424                     var hex = nibble_to_hex((b & 0xF0) >>> 4) 
425                             + nibble_to_hex(b &0x0F);
426                     buffer += '%'+hex;
427                }
428             }
429             return buffer;    
430              
431         },
432
433         /**
434          * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
435          * @param {String} string
436          * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
437          * @return {Object} A literal with members
438          */
439         urlDecode : function(string, overwrite){
440             if(!string || !string.length){
441                 return {};
442             }
443             var obj = {};
444             var pairs = string.split('&');
445             var pair, name, value;
446             for(var i = 0, len = pairs.length; i < len; i++){
447                 pair = pairs[i].split('=');
448                 name = decodeURIComponent(pair[0]);
449                 value = decodeURIComponent(pair[1]);
450                 if(overwrite !== true){
451                     if(typeof obj[name] == "undefined"){
452                         obj[name] = value;
453                     }else if(typeof obj[name] == "string"){
454                         obj[name] = [obj[name]];
455                         obj[name].push(value);
456                     }else{
457                         obj[name].push(value);
458                     }
459                 }else{
460                     obj[name] = value;
461                 }
462             }
463             return obj;
464         },
465
466         /**
467          * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
468          * passed array is not really an array, your function is called once with it.
469          * The supplied function is called with (Object item, Number index, Array allItems).
470          * @param {Array/NodeList/Mixed} array
471          * @param {Function} fn
472          * @param {Object} scope
473          */
474         each : function(array, fn, scope){
475             if(typeof array.length == "undefined" || typeof array == "string"){
476                 array = [array];
477             }
478             for(var i = 0, len = array.length; i < len; i++){
479                 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
480             }
481         },
482
483         // deprecated
484         combine : function(){
485             var as = arguments, l = as.length, r = [];
486             for(var i = 0; i < l; i++){
487                 var a = as[i];
488                 if(a instanceof Array){
489                     r = r.concat(a);
490                 }else if(a.length !== undefined && !a.substr){
491                     r = r.concat(Array.prototype.slice.call(a, 0));
492                 }else{
493                     r.push(a);
494                 }
495             }
496             return r;
497         },
498
499         /**
500          * Escapes the passed string for use in a regular expression
501          * @param {String} str
502          * @return {String}
503          */
504         escapeRe : function(s) {
505             return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
506         },
507
508         // internal
509         callback : function(cb, scope, args, delay){
510             if(typeof cb == "function"){
511                 if(delay){
512                     cb.defer(delay, scope, args || []);
513                 }else{
514                     cb.apply(scope, args || []);
515                 }
516             }
517         },
518
519         /**
520          * Return the dom node for the passed string (id), dom node, or Roo.Element
521          * @param {String/HTMLElement/Roo.Element} el
522          * @return HTMLElement
523          */
524         getDom : function(el){
525             if(!el){
526                 return null;
527             }
528             return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
529         },
530
531         /**
532         * Shorthand for {@link Roo.ComponentMgr#get}
533         * @param {String} id
534         * @return Roo.Component
535         */
536         getCmp : function(id){
537             return Roo.ComponentMgr.get(id);
538         },
539          
540         num : function(v, defaultValue){
541             if(typeof v != 'number'){
542                 return defaultValue;
543             }
544             return v;
545         },
546
547         destroy : function(){
548             for(var i = 0, a = arguments, len = a.length; i < len; i++) {
549                 var as = a[i];
550                 if(as){
551                     if(as.dom){
552                         as.removeAllListeners();
553                         as.remove();
554                         continue;
555                     }
556                     if(typeof as.purgeListeners == 'function'){
557                         as.purgeListeners();
558                     }
559                     if(typeof as.destroy == 'function'){
560                         as.destroy();
561                     }
562                 }
563             }
564         },
565
566         // inpired by a similar function in mootools library
567         /**
568          * Returns the type of object that is passed in. If the object passed in is null or undefined it
569          * return false otherwise it returns one of the following values:<ul>
570          * <li><b>string</b>: If the object passed is a string</li>
571          * <li><b>number</b>: If the object passed is a number</li>
572          * <li><b>boolean</b>: If the object passed is a boolean value</li>
573          * <li><b>function</b>: If the object passed is a function reference</li>
574          * <li><b>object</b>: If the object passed is an object</li>
575          * <li><b>array</b>: If the object passed is an array</li>
576          * <li><b>regexp</b>: If the object passed is a regular expression</li>
577          * <li><b>element</b>: If the object passed is a DOM Element</li>
578          * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
579          * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
580          * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
581          * @param {Mixed} object
582          * @return {String}
583          */
584         type : function(o){
585             if(o === undefined || o === null){
586                 return false;
587             }
588             if(o.htmlElement){
589                 return 'element';
590             }
591             var t = typeof o;
592             if(t == 'object' && o.nodeName) {
593                 switch(o.nodeType) {
594                     case 1: return 'element';
595                     case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
596                 }
597             }
598             if(t == 'object' || t == 'function') {
599                 switch(o.constructor) {
600                     case Array: return 'array';
601                     case RegExp: return 'regexp';
602                 }
603                 if(typeof o.length == 'number' && typeof o.item == 'function') {
604                     return 'nodelist';
605                 }
606             }
607             return t;
608         },
609
610         /**
611          * Returns true if the passed value is null, undefined or an empty string (optional).
612          * @param {Mixed} value The value to test
613          * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
614          * @return {Boolean}
615          */
616         isEmpty : function(v, allowBlank){
617             return v === null || v === undefined || (!allowBlank ? v === '' : false);
618         },
619         
620         /** @type Boolean */
621         isOpera : isOpera,
622         /** @type Boolean */
623         isSafari : isSafari,
624         /** @type Boolean */
625         isFirefox : isFirefox,
626         /** @type Boolean */
627         isIE : isIE,
628         /** @type Boolean */
629         isIE7 : isIE7,
630         /** @type Boolean */
631         isIE11 : isIE11,
632         /** @type Boolean */
633         isEdge : isEdge,
634         /** @type Boolean */
635         isGecko : isGecko,
636         /** @type Boolean */
637         isBorderBox : isBorderBox,
638         /** @type Boolean */
639         isWindows : isWindows,
640         /** @type Boolean */
641         isLinux : isLinux,
642         /** @type Boolean */
643         isMac : isMac,
644         /** @type Boolean */
645         isIOS : isIOS,
646         /** @type Boolean */
647         isAndroid : isAndroid,
648         /** @type Boolean */
649         isTouch : isTouch,
650
651         /**
652          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
653          * you may want to set this to true.
654          * @type Boolean
655          */
656         useShims : ((isIE && !isIE7) || (isGecko && isMac)),
657         
658         
659                 
660         /**
661          * Selects a single element as a Roo Element
662          * This is about as close as you can get to jQuery's $('do crazy stuff')
663          * @param {String} selector The selector/xpath query
664          * @param {Node} root (optional) The start of the query (defaults to document).
665          * @return {Roo.Element}
666          */
667         selectNode : function(selector, root) 
668         {
669             var node = Roo.DomQuery.selectNode(selector,root);
670             return node ? Roo.get(node) : new Roo.Element(false);
671         },
672                 /**
673                  * Find the current bootstrap width Grid size
674                  * Note xs is the default for smaller.. - this is currently used by grids to render correct columns
675                  * @returns {String} (xs|sm|md|lg|xl)
676                  */
677                 
678                 getGridSize : function()
679                 {
680                         var w = Roo.lib.Dom.getViewWidth();
681                         switch(true) {
682                                 case w > 1200:
683                                         return 'xl';
684                                 case w > 992:
685                                         return 'lg';
686                                 case w > 768:
687                                         return 'md';
688                                 case w > 576:
689                                         return 'sm';
690                                 default:
691                                         return 'xs'
692                         }
693                         
694                 }
695         
696     });
697
698
699 })();
700
701 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
702                 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
703                 "Roo.app", "Roo.ux" 
704                );
705 /*
706  * Based on:
707  * Ext JS Library 1.1.1
708  * Copyright(c) 2006-2007, Ext JS, LLC.
709  *
710  * Originally Released Under LGPL - original licence link has changed is not relivant.
711  *
712  * Fork - LGPL
713  * <script type="text/javascript">
714  */
715
716 (function() {    
717     // wrappedn so fnCleanup is not in global scope...
718     if(Roo.isIE) {
719         function fnCleanUp() {
720             var p = Function.prototype;
721             delete p.createSequence;
722             delete p.defer;
723             delete p.createDelegate;
724             delete p.createCallback;
725             delete p.createInterceptor;
726
727             window.detachEvent("onunload", fnCleanUp);
728         }
729         window.attachEvent("onunload", fnCleanUp);
730     }
731 })();
732
733
734 /**
735  * @class Function
736  * These functions are available on every Function object (any JavaScript function).
737  */
738 Roo.apply(Function.prototype, {
739      /**
740      * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
741      * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
742      * Will create a function that is bound to those 2 args.
743      * @return {Function} The new function
744     */
745     createCallback : function(/*args...*/){
746         // make args available, in function below
747         var args = arguments;
748         var method = this;
749         return function() {
750             return method.apply(window, args);
751         };
752     },
753
754     /**
755      * Creates a delegate (callback) that sets the scope to obj.
756      * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
757      * Will create a function that is automatically scoped to this.
758      * @param {Object} obj (optional) The object for which the scope is set
759      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
760      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
761      *                                             if a number the args are inserted at the specified position
762      * @return {Function} The new function
763      */
764     createDelegate : function(obj, args, appendArgs){
765         var method = this;
766         return function() {
767             var callArgs = args || arguments;
768             if(appendArgs === true){
769                 callArgs = Array.prototype.slice.call(arguments, 0);
770                 callArgs = callArgs.concat(args);
771             }else if(typeof appendArgs == "number"){
772                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
773                 var applyArgs = [appendArgs, 0].concat(args); // create method call params
774                 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
775             }
776             return method.apply(obj || window, callArgs);
777         };
778     },
779
780     /**
781      * Calls this function after the number of millseconds specified.
782      * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
783      * @param {Object} obj (optional) The object for which the scope is set
784      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
785      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
786      *                                             if a number the args are inserted at the specified position
787      * @return {Number} The timeout id that can be used with clearTimeout
788      */
789     defer : function(millis, obj, args, appendArgs){
790         var fn = this.createDelegate(obj, args, appendArgs);
791         if(millis){
792             return setTimeout(fn, millis);
793         }
794         fn();
795         return 0;
796     },
797     /**
798      * Create a combined function call sequence of the original function + the passed function.
799      * The resulting function returns the results of the original function.
800      * The passed fcn is called with the parameters of the original function
801      * @param {Function} fcn The function to sequence
802      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
803      * @return {Function} The new function
804      */
805     createSequence : function(fcn, scope){
806         if(typeof fcn != "function"){
807             return this;
808         }
809         var method = this;
810         return function() {
811             var retval = method.apply(this || window, arguments);
812             fcn.apply(scope || this || window, arguments);
813             return retval;
814         };
815     },
816
817     /**
818      * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
819      * The resulting function returns the results of the original function.
820      * The passed fcn is called with the parameters of the original function.
821      * @addon
822      * @param {Function} fcn The function to call before the original
823      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
824      * @return {Function} The new function
825      */
826     createInterceptor : function(fcn, scope){
827         if(typeof fcn != "function"){
828             return this;
829         }
830         var method = this;
831         return function() {
832             fcn.target = this;
833             fcn.method = method;
834             if(fcn.apply(scope || this || window, arguments) === false){
835                 return;
836             }
837             return method.apply(this || window, arguments);
838         };
839     }
840 });
841 /*
842  * Based on:
843  * Ext JS Library 1.1.1
844  * Copyright(c) 2006-2007, Ext JS, LLC.
845  *
846  * Originally Released Under LGPL - original licence link has changed is not relivant.
847  *
848  * Fork - LGPL
849  * <script type="text/javascript">
850  */
851
852 Roo.applyIf(String, {
853     
854     /** @scope String */
855     
856     /**
857      * Escapes the passed string for ' and \
858      * @param {String} string The string to escape
859      * @return {String} The escaped string
860      * @static
861      */
862     escape : function(string) {
863         return string.replace(/('|\\)/g, "\\$1");
864     },
865
866     /**
867      * Pads the left side of a string with a specified character.  This is especially useful
868      * for normalizing number and date strings.  Example usage:
869      * <pre><code>
870 var s = String.leftPad('123', 5, '0');
871 // s now contains the string: '00123'
872 </code></pre>
873      * @param {String} string The original string
874      * @param {Number} size The total length of the output string
875      * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
876      * @return {String} The padded string
877      * @static
878      */
879     leftPad : function (val, size, ch) {
880         var result = new String(val);
881         if(ch === null || ch === undefined || ch === '') {
882             ch = " ";
883         }
884         while (result.length < size) {
885             result = ch + result;
886         }
887         return result;
888     },
889
890     /**
891      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
892      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
893      * <pre><code>
894 var cls = 'my-class', text = 'Some text';
895 var s = String.format('<div class="{0}">{1}</div>', cls, text);
896 // s now contains the string: '<div class="my-class">Some text</div>'
897 </code></pre>
898      * @param {String} string The tokenized string to be formatted
899      * @param {String} value1 The value to replace token {0}
900      * @param {String} value2 Etc...
901      * @return {String} The formatted string
902      * @static
903      */
904     format : function(format){
905         var args = Array.prototype.slice.call(arguments, 1);
906         return format.replace(/\{(\d+)\}/g, function(m, i){
907             return Roo.util.Format.htmlEncode(args[i]);
908         });
909     }
910   
911     
912 });
913
914 /**
915  * Utility function that allows you to easily switch a string between two alternating values.  The passed value
916  * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
917  * they are already different, the first value passed in is returned.  Note that this method returns the new value
918  * but does not change the current string.
919  * <pre><code>
920 // alternate sort directions
921 sort = sort.toggle('ASC', 'DESC');
922
923 // instead of conditional logic:
924 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
925 </code></pre>
926  * @param {String} value The value to compare to the current string
927  * @param {String} other The new value to use if the string already equals the first value passed in
928  * @return {String} The new value
929  */
930  
931 String.prototype.toggle = function(value, other){
932     return this == value ? other : value;
933 };
934
935
936 /**
937   * Remove invalid unicode characters from a string 
938   *
939   * @return {String} The clean string
940   */
941 String.prototype.unicodeClean = function () {
942     return this.replace(/[\s\S]/g,
943         function(character) {
944             if (character.charCodeAt()< 256) {
945               return character;
946            }
947            try {
948                 encodeURIComponent(character);
949            } catch(e) { 
950               return '';
951            }
952            return character;
953         }
954     );
955 };
956   
957
958 /**
959   * Make the first letter of a string uppercase
960   *
961   * @return {String} The new string.
962   */
963 String.prototype.toUpperCaseFirst = function () {
964     return this.charAt(0).toUpperCase() + this.slice(1);
965 };  
966   
967 /*
968  * Based on:
969  * Ext JS Library 1.1.1
970  * Copyright(c) 2006-2007, Ext JS, LLC.
971  *
972  * Originally Released Under LGPL - original licence link has changed is not relivant.
973  *
974  * Fork - LGPL
975  * <script type="text/javascript">
976  */
977
978  /**
979  * @class Number
980  */
981 Roo.applyIf(Number.prototype, {
982     /**
983      * Checks whether or not the current number is within a desired range.  If the number is already within the
984      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
985      * exceeded.  Note that this method returns the constrained value but does not change the current number.
986      * @param {Number} min The minimum number in the range
987      * @param {Number} max The maximum number in the range
988      * @return {Number} The constrained value if outside the range, otherwise the current value
989      */
990     constrain : function(min, max){
991         return Math.min(Math.max(this, min), max);
992     }
993 });/*
994  * Based on:
995  * Ext JS Library 1.1.1
996  * Copyright(c) 2006-2007, Ext JS, LLC.
997  *
998  * Originally Released Under LGPL - original licence link has changed is not relivant.
999  *
1000  * Fork - LGPL
1001  * <script type="text/javascript">
1002  */
1003  /**
1004  * @class Array
1005  */
1006 Roo.applyIf(Array.prototype, {
1007     /**
1008      * 
1009      * Checks whether or not the specified object exists in the array.
1010      * @param {Object} o The object to check for
1011      * @return {Number} The index of o in the array (or -1 if it is not found)
1012      */
1013     indexOf : function(o){
1014        for (var i = 0, len = this.length; i < len; i++){
1015               if(this[i] == o) { return i; }
1016        }
1017            return -1;
1018     },
1019
1020     /**
1021      * Removes the specified object from the array.  If the object is not found nothing happens.
1022      * @param {Object} o The object to remove
1023      */
1024     remove : function(o){
1025        var index = this.indexOf(o);
1026        if(index != -1){
1027            this.splice(index, 1);
1028        }
1029     },
1030     /**
1031      * Map (JS 1.6 compatibility)
1032      * @param {Function} function  to call
1033      */
1034     map : function(fun )
1035     {
1036         var len = this.length >>> 0;
1037         if (typeof fun != "function") {
1038             throw new TypeError();
1039         }
1040         var res = new Array(len);
1041         var thisp = arguments[1];
1042         for (var i = 0; i < len; i++)
1043         {
1044             if (i in this) {
1045                 res[i] = fun.call(thisp, this[i], i, this);
1046             }
1047         }
1048
1049         return res;
1050     },
1051     /**
1052      * equals
1053      * @param {Array} o The array to compare to
1054      * @returns {Boolean} true if the same
1055      */
1056     equals : function(b)
1057     {
1058             // https://stackoverflow.com/questions/3115982/how-to-check-if-two-arrays-are-equal-with-javascript
1059         if (this === b) {
1060             return true;
1061         }
1062         if (b == null) {
1063             return false;
1064         }
1065         if (this.length !== b.length) {
1066             return false;
1067         }
1068           
1069         // sort?? a.sort().equals(b.sort());
1070           
1071         for (var i = 0; i < this.length; ++i) {
1072             if (this[i] !== b[i]) {
1073             return false;
1074             }
1075         }
1076         return true;
1077     } 
1078     
1079     
1080     
1081     
1082 });
1083
1084 Roo.applyIf(Array, {
1085  /**
1086      * from
1087      * @static
1088      * @param {Array} o Or Array like object (eg. nodelist)
1089      * @returns {Array} 
1090      */
1091     from : function(o)
1092     {
1093         var ret= [];
1094     
1095         for (var i =0; i < o.length; i++) { 
1096             ret[i] = o[i];
1097         }
1098         return ret;
1099       
1100     }
1101 });
1102 /*
1103  * Based on:
1104  * Ext JS Library 1.1.1
1105  * Copyright(c) 2006-2007, Ext JS, LLC.
1106  *
1107  * Originally Released Under LGPL - original licence link has changed is not relivant.
1108  *
1109  * Fork - LGPL
1110  * <script type="text/javascript">
1111  */
1112
1113 /**
1114  * @class Date
1115  *
1116  * The date parsing and format syntax is a subset of
1117  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
1118  * supported will provide results equivalent to their PHP versions.
1119  *
1120  * Following is the list of all currently supported formats:
1121  *<pre>
1122 Sample date:
1123 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1124
1125 Format  Output      Description
1126 ------  ----------  --------------------------------------------------------------
1127   d      10         Day of the month, 2 digits with leading zeros
1128   D      Wed        A textual representation of a day, three letters
1129   j      10         Day of the month without leading zeros
1130   l      Wednesday  A full textual representation of the day of the week
1131   S      th         English ordinal day of month suffix, 2 chars (use with j)
1132   w      3          Numeric representation of the day of the week
1133   z      9          The julian date, or day of the year (0-365)
1134   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1135   F      January    A full textual representation of the month
1136   m      01         Numeric representation of a month, with leading zeros
1137   M      Jan        Month name abbreviation, three letters
1138   n      1          Numeric representation of a month, without leading zeros
1139   t      31         Number of days in the given month
1140   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
1141   Y      2007       A full numeric representation of a year, 4 digits
1142   y      07         A two digit representation of a year
1143   a      pm         Lowercase Ante meridiem and Post meridiem
1144   A      PM         Uppercase Ante meridiem and Post meridiem
1145   g      3          12-hour format of an hour without leading zeros
1146   G      15         24-hour format of an hour without leading zeros
1147   h      03         12-hour format of an hour with leading zeros
1148   H      15         24-hour format of an hour with leading zeros
1149   i      05         Minutes with leading zeros
1150   s      01         Seconds, with leading zeros
1151   O      -0600      Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1152   P      -06:00     Difference to Greenwich time (GMT) with colon between hours and minutes
1153   T      CST        Timezone setting of the machine running the code
1154   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
1155 </pre>
1156  *
1157  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1158  * <pre><code>
1159 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1160 document.write(dt.format('Y-m-d'));                         //2007-01-10
1161 document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
1162 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
1163  </code></pre>
1164  *
1165  * Here are some standard date/time patterns that you might find helpful.  They
1166  * are not part of the source of Date.js, but to use them you can simply copy this
1167  * block of code into any script that is included after Date.js and they will also become
1168  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
1169  * <pre><code>
1170 Date.patterns = {
1171     ISO8601Long:"Y-m-d H:i:s",
1172     ISO8601Short:"Y-m-d",
1173     ShortDate: "n/j/Y",
1174     LongDate: "l, F d, Y",
1175     FullDateTime: "l, F d, Y g:i:s A",
1176     MonthDay: "F d",
1177     ShortTime: "g:i A",
1178     LongTime: "g:i:s A",
1179     SortableDateTime: "Y-m-d\\TH:i:s",
1180     UniversalSortableDateTime: "Y-m-d H:i:sO",
1181     YearMonth: "F, Y"
1182 };
1183 </code></pre>
1184  *
1185  * Example usage:
1186  * <pre><code>
1187 var dt = new Date();
1188 document.write(dt.format(Date.patterns.ShortDate));
1189  </code></pre>
1190  */
1191
1192 /*
1193  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1194  * They generate precompiled functions from date formats instead of parsing and
1195  * processing the pattern every time you format a date.  These functions are available
1196  * on every Date object (any javascript function).
1197  *
1198  * The original article and download are here:
1199  * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1200  *
1201  */
1202  
1203  
1204  // was in core
1205 /**
1206  Returns the number of milliseconds between this date and date
1207  @param {Date} date (optional) Defaults to now
1208  @return {Number} The diff in milliseconds
1209  @member Date getElapsed
1210  */
1211 Date.prototype.getElapsed = function(date) {
1212         return Math.abs((date || new Date()).getTime()-this.getTime());
1213 };
1214 // was in date file..
1215
1216
1217 // private
1218 Date.parseFunctions = {count:0};
1219 // private
1220 Date.parseRegexes = [];
1221 // private
1222 Date.formatFunctions = {count:0};
1223
1224 // private
1225 Date.prototype.dateFormat = function(format) {
1226     if (Date.formatFunctions[format] == null) {
1227         Date.createNewFormat(format);
1228     }
1229     var func = Date.formatFunctions[format];
1230     return this[func]();
1231 };
1232
1233
1234 /**
1235  * Formats a date given the supplied format string
1236  * @param {String} format The format string
1237  * @return {String} The formatted date
1238  * @method
1239  */
1240 Date.prototype.format = Date.prototype.dateFormat;
1241
1242 // private
1243 Date.createNewFormat = function(format) {
1244     var funcName = "format" + Date.formatFunctions.count++;
1245     Date.formatFunctions[format] = funcName;
1246     var code = "Date.prototype." + funcName + " = function(){return ";
1247     var special = false;
1248     var ch = '';
1249     for (var i = 0; i < format.length; ++i) {
1250         ch = format.charAt(i);
1251         if (!special && ch == "\\") {
1252             special = true;
1253         }
1254         else if (special) {
1255             special = false;
1256             code += "'" + String.escape(ch) + "' + ";
1257         }
1258         else {
1259             code += Date.getFormatCode(ch);
1260         }
1261     }
1262     /** eval:var:zzzzzzzzzzzzz */
1263     eval(code.substring(0, code.length - 3) + ";}");
1264 };
1265
1266 // private
1267 Date.getFormatCode = function(character) {
1268     switch (character) {
1269     case "d":
1270         return "String.leftPad(this.getDate(), 2, '0') + ";
1271     case "D":
1272         return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1273     case "j":
1274         return "this.getDate() + ";
1275     case "l":
1276         return "Date.dayNames[this.getDay()] + ";
1277     case "S":
1278         return "this.getSuffix() + ";
1279     case "w":
1280         return "this.getDay() + ";
1281     case "z":
1282         return "this.getDayOfYear() + ";
1283     case "W":
1284         return "this.getWeekOfYear() + ";
1285     case "F":
1286         return "Date.monthNames[this.getMonth()] + ";
1287     case "m":
1288         return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1289     case "M":
1290         return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1291     case "n":
1292         return "(this.getMonth() + 1) + ";
1293     case "t":
1294         return "this.getDaysInMonth() + ";
1295     case "L":
1296         return "(this.isLeapYear() ? 1 : 0) + ";
1297     case "Y":
1298         return "this.getFullYear() + ";
1299     case "y":
1300         return "('' + this.getFullYear()).substring(2, 4) + ";
1301     case "a":
1302         return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1303     case "A":
1304         return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1305     case "g":
1306         return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1307     case "G":
1308         return "this.getHours() + ";
1309     case "h":
1310         return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1311     case "H":
1312         return "String.leftPad(this.getHours(), 2, '0') + ";
1313     case "i":
1314         return "String.leftPad(this.getMinutes(), 2, '0') + ";
1315     case "s":
1316         return "String.leftPad(this.getSeconds(), 2, '0') + ";
1317     case "O":
1318         return "this.getGMTOffset() + ";
1319     case "P":
1320         return "this.getGMTColonOffset() + ";
1321     case "T":
1322         return "this.getTimezone() + ";
1323     case "Z":
1324         return "(this.getTimezoneOffset() * -60) + ";
1325     default:
1326         return "'" + String.escape(character) + "' + ";
1327     }
1328 };
1329
1330 /**
1331  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1332  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1333  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1334  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1335  * string or the parse operation will fail.
1336  * Example Usage:
1337 <pre><code>
1338 //dt = Fri May 25 2007 (current date)
1339 var dt = new Date();
1340
1341 //dt = Thu May 25 2006 (today's month/day in 2006)
1342 dt = Date.parseDate("2006", "Y");
1343
1344 //dt = Sun Jan 15 2006 (all date parts specified)
1345 dt = Date.parseDate("2006-1-15", "Y-m-d");
1346
1347 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1348 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1349 </code></pre>
1350  * @param {String} input The unparsed date as a string
1351  * @param {String} format The format the date is in
1352  * @return {Date} The parsed date
1353  * @static
1354  */
1355 Date.parseDate = function(input, format) {
1356     if (Date.parseFunctions[format] == null) {
1357         Date.createParser(format);
1358     }
1359     var func = Date.parseFunctions[format];
1360     return Date[func](input);
1361 };
1362 /**
1363  * @private
1364  */
1365
1366 Date.createParser = function(format) {
1367     var funcName = "parse" + Date.parseFunctions.count++;
1368     var regexNum = Date.parseRegexes.length;
1369     var currentGroup = 1;
1370     Date.parseFunctions[format] = funcName;
1371
1372     var code = "Date." + funcName + " = function(input){\n"
1373         + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1374         + "var d = new Date();\n"
1375         + "y = d.getFullYear();\n"
1376         + "m = d.getMonth();\n"
1377         + "d = d.getDate();\n"
1378         + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1379         + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1380         + "if (results && results.length > 0) {";
1381     var regex = "";
1382
1383     var special = false;
1384     var ch = '';
1385     for (var i = 0; i < format.length; ++i) {
1386         ch = format.charAt(i);
1387         if (!special && ch == "\\") {
1388             special = true;
1389         }
1390         else if (special) {
1391             special = false;
1392             regex += String.escape(ch);
1393         }
1394         else {
1395             var obj = Date.formatCodeToRegex(ch, currentGroup);
1396             currentGroup += obj.g;
1397             regex += obj.s;
1398             if (obj.g && obj.c) {
1399                 code += obj.c;
1400             }
1401         }
1402     }
1403
1404     code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1405         + "{v = new Date(y, m, d, h, i, s); v.setFullYear(y);}\n"
1406         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1407         + "{v = new Date(y, m, d, h, i); v.setFullYear(y);}\n"
1408         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1409         + "{v = new Date(y, m, d, h); v.setFullYear(y);}\n"
1410         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1411         + "{v = new Date(y, m, d); v.setFullYear(y);}\n"
1412         + "else if (y >= 0 && m >= 0)\n"
1413         + "{v = new Date(y, m); v.setFullYear(y);}\n"
1414         + "else if (y >= 0)\n"
1415         + "{v = new Date(y); v.setFullYear(y);}\n"
1416         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1417         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1418         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1419         + ";}";
1420
1421     Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1422     /** eval:var:zzzzzzzzzzzzz */
1423     eval(code);
1424 };
1425
1426 // private
1427 Date.formatCodeToRegex = function(character, currentGroup) {
1428     switch (character) {
1429     case "D":
1430         return {g:0,
1431         c:null,
1432         s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1433     case "j":
1434         return {g:1,
1435             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1436             s:"(\\d{1,2})"}; // day of month without leading zeroes
1437     case "d":
1438         return {g:1,
1439             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1440             s:"(\\d{2})"}; // day of month with leading zeroes
1441     case "l":
1442         return {g:0,
1443             c:null,
1444             s:"(?:" + Date.dayNames.join("|") + ")"};
1445     case "S":
1446         return {g:0,
1447             c:null,
1448             s:"(?:st|nd|rd|th)"};
1449     case "w":
1450         return {g:0,
1451             c:null,
1452             s:"\\d"};
1453     case "z":
1454         return {g:0,
1455             c:null,
1456             s:"(?:\\d{1,3})"};
1457     case "W":
1458         return {g:0,
1459             c:null,
1460             s:"(?:\\d{2})"};
1461     case "F":
1462         return {g:1,
1463             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1464             s:"(" + Date.monthNames.join("|") + ")"};
1465     case "M":
1466         return {g:1,
1467             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1468             s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1469     case "n":
1470         return {g:1,
1471             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1472             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1473     case "m":
1474         return {g:1,
1475             c:"m = Math.max(0,parseInt(results[" + currentGroup + "], 10) - 1);\n",
1476             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1477     case "t":
1478         return {g:0,
1479             c:null,
1480             s:"\\d{1,2}"};
1481     case "L":
1482         return {g:0,
1483             c:null,
1484             s:"(?:1|0)"};
1485     case "Y":
1486         return {g:1,
1487             c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1488             s:"(\\d{4})"};
1489     case "y":
1490         return {g:1,
1491             c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1492                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1493             s:"(\\d{1,2})"};
1494     case "a":
1495         return {g:1,
1496             c:"if (results[" + currentGroup + "] == 'am') {\n"
1497                 + "if (h == 12) { h = 0; }\n"
1498                 + "} else { if (h < 12) { h += 12; }}",
1499             s:"(am|pm)"};
1500     case "A":
1501         return {g:1,
1502             c:"if (results[" + currentGroup + "] == 'AM') {\n"
1503                 + "if (h == 12) { h = 0; }\n"
1504                 + "} else { if (h < 12) { h += 12; }}",
1505             s:"(AM|PM)"};
1506     case "g":
1507     case "G":
1508         return {g:1,
1509             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1510             s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
1511     case "h":
1512     case "H":
1513         return {g:1,
1514             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1515             s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
1516     case "i":
1517         return {g:1,
1518             c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1519             s:"(\\d{2})"};
1520     case "s":
1521         return {g:1,
1522             c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1523             s:"(\\d{2})"};
1524     case "O":
1525         return {g:1,
1526             c:[
1527                 "o = results[", currentGroup, "];\n",
1528                 "var sn = o.substring(0,1);\n", // get + / - sign
1529                 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1530                 "var mn = o.substring(3,5) % 60;\n", // get minutes
1531                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1532                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1533             ].join(""),
1534             s:"([+\-]\\d{2,4})"};
1535     
1536     
1537     case "P":
1538         return {g:1,
1539                 c:[
1540                    "o = results[", currentGroup, "];\n",
1541                    "var sn = o.substring(0,1);\n",
1542                    "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1543                    "var mn = o.substring(4,6) % 60;\n",
1544                    "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1545                         "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1546             ].join(""),
1547             s:"([+\-]\\d{4})"};
1548     case "T":
1549         return {g:0,
1550             c:null,
1551             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1552     case "Z":
1553         return {g:1,
1554             c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1555                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1556             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1557     default:
1558         return {g:0,
1559             c:null,
1560             s:String.escape(character)};
1561     }
1562 };
1563
1564 /**
1565  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1566  * @return {String} The abbreviated timezone name (e.g. 'CST')
1567  */
1568 Date.prototype.getTimezone = function() {
1569     return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1570 };
1571
1572 /**
1573  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1574  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1575  */
1576 Date.prototype.getGMTOffset = function() {
1577     return (this.getTimezoneOffset() > 0 ? "-" : "+")
1578         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1579         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1580 };
1581
1582 /**
1583  * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1584  * @return {String} 2-characters representing hours and 2-characters representing minutes
1585  * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1586  */
1587 Date.prototype.getGMTColonOffset = function() {
1588         return (this.getTimezoneOffset() > 0 ? "-" : "+")
1589                 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1590                 + ":"
1591                 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1592 }
1593
1594 /**
1595  * Get the numeric day number of the year, adjusted for leap year.
1596  * @return {Number} 0 through 364 (365 in leap years)
1597  */
1598 Date.prototype.getDayOfYear = function() {
1599     var num = 0;
1600     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1601     for (var i = 0; i < this.getMonth(); ++i) {
1602         num += Date.daysInMonth[i];
1603     }
1604     return num + this.getDate() - 1;
1605 };
1606
1607 /**
1608  * Get the string representation of the numeric week number of the year
1609  * (equivalent to the format specifier 'W').
1610  * @return {String} '00' through '52'
1611  */
1612 Date.prototype.getWeekOfYear = function() {
1613     // Skip to Thursday of this week
1614     var now = this.getDayOfYear() + (4 - this.getDay());
1615     // Find the first Thursday of the year
1616     var jan1 = new Date(this.getFullYear(), 0, 1);
1617     var then = (7 - jan1.getDay() + 4);
1618     return String.leftPad(((now - then) / 7) + 1, 2, "0");
1619 };
1620
1621 /**
1622  * Whether or not the current date is in a leap year.
1623  * @return {Boolean} True if the current date is in a leap year, else false
1624  */
1625 Date.prototype.isLeapYear = function() {
1626     var year = this.getFullYear();
1627     return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1628 };
1629
1630 /**
1631  * Get the first day of the current month, adjusted for leap year.  The returned value
1632  * is the numeric day index within the week (0-6) which can be used in conjunction with
1633  * the {@link #monthNames} array to retrieve the textual day name.
1634  * Example:
1635  *<pre><code>
1636 var dt = new Date('1/10/2007');
1637 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1638 </code></pre>
1639  * @return {Number} The day number (0-6)
1640  */
1641 Date.prototype.getFirstDayOfMonth = function() {
1642     var day = (this.getDay() - (this.getDate() - 1)) % 7;
1643     return (day < 0) ? (day + 7) : day;
1644 };
1645
1646 /**
1647  * Get the last day of the current month, adjusted for leap year.  The returned value
1648  * is the numeric day index within the week (0-6) which can be used in conjunction with
1649  * the {@link #monthNames} array to retrieve the textual day name.
1650  * Example:
1651  *<pre><code>
1652 var dt = new Date('1/10/2007');
1653 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1654 </code></pre>
1655  * @return {Number} The day number (0-6)
1656  */
1657 Date.prototype.getLastDayOfMonth = function() {
1658     var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1659     return (day < 0) ? (day + 7) : day;
1660 };
1661
1662
1663 /**
1664  * Get the first date of this date's month
1665  * @return {Date}
1666  */
1667 Date.prototype.getFirstDateOfMonth = function() {
1668     return new Date(this.getFullYear(), this.getMonth(), 1);
1669 };
1670
1671 /**
1672  * Get the last date of this date's month
1673  * @return {Date}
1674  */
1675 Date.prototype.getLastDateOfMonth = function() {
1676     return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1677 };
1678 /**
1679  * Get the number of days in the current month, adjusted for leap year.
1680  * @return {Number} The number of days in the month
1681  */
1682 Date.prototype.getDaysInMonth = function() {
1683     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1684     return Date.daysInMonth[this.getMonth()];
1685 };
1686
1687 /**
1688  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1689  * @return {String} 'st, 'nd', 'rd' or 'th'
1690  */
1691 Date.prototype.getSuffix = function() {
1692     switch (this.getDate()) {
1693         case 1:
1694         case 21:
1695         case 31:
1696             return "st";
1697         case 2:
1698         case 22:
1699             return "nd";
1700         case 3:
1701         case 23:
1702             return "rd";
1703         default:
1704             return "th";
1705     }
1706 };
1707
1708 // private
1709 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1710
1711 /**
1712  * An array of textual month names.
1713  * Override these values for international dates, for example...
1714  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1715  * @type Array
1716  * @static
1717  */
1718 Date.monthNames =
1719    ["January",
1720     "February",
1721     "March",
1722     "April",
1723     "May",
1724     "June",
1725     "July",
1726     "August",
1727     "September",
1728     "October",
1729     "November",
1730     "December"];
1731
1732 /**
1733  * An array of textual day names.
1734  * Override these values for international dates, for example...
1735  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1736  * @type Array
1737  * @static
1738  */
1739 Date.dayNames =
1740    ["Sunday",
1741     "Monday",
1742     "Tuesday",
1743     "Wednesday",
1744     "Thursday",
1745     "Friday",
1746     "Saturday"];
1747
1748 // private
1749 Date.y2kYear = 50;
1750 // private
1751 Date.monthNumbers = {
1752     Jan:0,
1753     Feb:1,
1754     Mar:2,
1755     Apr:3,
1756     May:4,
1757     Jun:5,
1758     Jul:6,
1759     Aug:7,
1760     Sep:8,
1761     Oct:9,
1762     Nov:10,
1763     Dec:11};
1764
1765 /**
1766  * Creates and returns a new Date instance with the exact same date value as the called instance.
1767  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1768  * variable will also be changed.  When the intention is to create a new variable that will not
1769  * modify the original instance, you should create a clone.
1770  *
1771  * Example of correctly cloning a date:
1772  * <pre><code>
1773 //wrong way:
1774 var orig = new Date('10/1/2006');
1775 var copy = orig;
1776 copy.setDate(5);
1777 document.write(orig);  //returns 'Thu Oct 05 2006'!
1778
1779 //correct way:
1780 var orig = new Date('10/1/2006');
1781 var copy = orig.clone();
1782 copy.setDate(5);
1783 document.write(orig);  //returns 'Thu Oct 01 2006'
1784 </code></pre>
1785  * @return {Date} The new Date instance
1786  */
1787 Date.prototype.clone = function() {
1788         return new Date(this.getTime());
1789 };
1790
1791 /**
1792  * Clears any time information from this date
1793  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1794  @return {Date} this or the clone
1795  */
1796 Date.prototype.clearTime = function(clone){
1797     if(clone){
1798         return this.clone().clearTime();
1799     }
1800     this.setHours(0);
1801     this.setMinutes(0);
1802     this.setSeconds(0);
1803     this.setMilliseconds(0);
1804     return this;
1805 };
1806
1807 // private
1808 // safari setMonth is broken -- check that this is only donw once...
1809 if(Roo.isSafari && typeof(Date.brokenSetMonth) == 'undefined'){
1810     Date.brokenSetMonth = Date.prototype.setMonth;
1811         Date.prototype.setMonth = function(num){
1812                 if(num <= -1){
1813                         var n = Math.ceil(-num);
1814                         var back_year = Math.ceil(n/12);
1815                         var month = (n % 12) ? 12 - n % 12 : 0 ;
1816                         this.setFullYear(this.getFullYear() - back_year);
1817                         return Date.brokenSetMonth.call(this, month);
1818                 } else {
1819                         return Date.brokenSetMonth.apply(this, arguments);
1820                 }
1821         };
1822 }
1823
1824 /** Date interval constant 
1825 * @static 
1826 * @type String */
1827 Date.MILLI = "ms";
1828 /** Date interval constant 
1829 * @static 
1830 * @type String */
1831 Date.SECOND = "s";
1832 /** Date interval constant 
1833 * @static 
1834 * @type String */
1835 Date.MINUTE = "mi";
1836 /** Date interval constant 
1837 * @static 
1838 * @type String */
1839 Date.HOUR = "h";
1840 /** Date interval constant 
1841 * @static 
1842 * @type String */
1843 Date.DAY = "d";
1844 /** Date interval constant 
1845 * @static 
1846 * @type String */
1847 Date.MONTH = "mo";
1848 /** Date interval constant 
1849 * @static 
1850 * @type String */
1851 Date.YEAR = "y";
1852
1853 /**
1854  * Provides a convenient method of performing basic date arithmetic.  This method
1855  * does not modify the Date instance being called - it creates and returns
1856  * a new Date instance containing the resulting date value.
1857  *
1858  * Examples:
1859  * <pre><code>
1860 //Basic usage:
1861 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1862 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1863
1864 //Negative values will subtract correctly:
1865 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1866 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1867
1868 //You can even chain several calls together in one line!
1869 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1870 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1871  </code></pre>
1872  *
1873  * @param {String} interval   A valid date interval enum value
1874  * @param {Number} value      The amount to add to the current date
1875  * @return {Date} The new Date instance
1876  */
1877 Date.prototype.add = function(interval, value){
1878   var d = this.clone();
1879   if (!interval || value === 0) { return d; }
1880   switch(interval.toLowerCase()){
1881     case Date.MILLI:
1882       d.setMilliseconds(this.getMilliseconds() + value);
1883       break;
1884     case Date.SECOND:
1885       d.setSeconds(this.getSeconds() + value);
1886       break;
1887     case Date.MINUTE:
1888       d.setMinutes(this.getMinutes() + value);
1889       break;
1890     case Date.HOUR:
1891       d.setHours(this.getHours() + value);
1892       break;
1893     case Date.DAY:
1894       d.setDate(this.getDate() + value);
1895       break;
1896     case Date.MONTH:
1897       var day = this.getDate();
1898       if(day > 28){
1899           day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1900       }
1901       d.setDate(day);
1902       d.setMonth(this.getMonth() + value);
1903       break;
1904     case Date.YEAR:
1905       d.setFullYear(this.getFullYear() + value);
1906       break;
1907   }
1908   return d;
1909 };
1910 /**
1911  * @class Roo.lib.Dom
1912  * @licence LGPL
1913  * @static
1914  * 
1915  * Dom utils (from YIU afaik)
1916  *
1917  * 
1918  **/
1919 Roo.lib.Dom = {
1920     /**
1921      * Get the view width
1922      * @param {Boolean} full True will get the full document, otherwise it's the view width
1923      * @return {Number} The width
1924      */
1925      
1926     getViewWidth : function(full) {
1927         return full ? this.getDocumentWidth() : this.getViewportWidth();
1928     },
1929     /**
1930      * Get the view height
1931      * @param {Boolean} full True will get the full document, otherwise it's the view height
1932      * @return {Number} The height
1933      */
1934     getViewHeight : function(full) {
1935         return full ? this.getDocumentHeight() : this.getViewportHeight();
1936     },
1937     /**
1938      * Get the Full Document height 
1939      * @return {Number} The height
1940      */
1941     getDocumentHeight: function() {
1942         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1943         return Math.max(scrollHeight, this.getViewportHeight());
1944     },
1945     /**
1946      * Get the Full Document width
1947      * @return {Number} The width
1948      */
1949     getDocumentWidth: function() {
1950         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1951         return Math.max(scrollWidth, this.getViewportWidth());
1952     },
1953     /**
1954      * Get the Window Viewport height
1955      * @return {Number} The height
1956      */
1957     getViewportHeight: function() {
1958         var height = self.innerHeight;
1959         var mode = document.compatMode;
1960
1961         if ((mode || Roo.isIE) && !Roo.isOpera) {
1962             height = (mode == "CSS1Compat") ?
1963                      document.documentElement.clientHeight :
1964                      document.body.clientHeight;
1965         }
1966
1967         return height;
1968     },
1969     /**
1970      * Get the Window Viewport width
1971      * @return {Number} The width
1972      */
1973     getViewportWidth: function() {
1974         var width = self.innerWidth;
1975         var mode = document.compatMode;
1976
1977         if (mode || Roo.isIE) {
1978             width = (mode == "CSS1Compat") ?
1979                     document.documentElement.clientWidth :
1980                     document.body.clientWidth;
1981         }
1982         return width;
1983     },
1984
1985     isAncestor : function(p, c) {
1986         p = Roo.getDom(p);
1987         c = Roo.getDom(c);
1988         if (!p || !c) {
1989             return false;
1990         }
1991
1992         if (p.contains && !Roo.isSafari) {
1993             return p.contains(c);
1994         } else if (p.compareDocumentPosition) {
1995             return !!(p.compareDocumentPosition(c) & 16);
1996         } else {
1997             var parent = c.parentNode;
1998             while (parent) {
1999                 if (parent == p) {
2000                     return true;
2001                 }
2002                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
2003                     return false;
2004                 }
2005                 parent = parent.parentNode;
2006             }
2007             return false;
2008         }
2009     },
2010
2011     getRegion : function(el) {
2012         return Roo.lib.Region.getRegion(el);
2013     },
2014
2015     getY : function(el) {
2016         return this.getXY(el)[1];
2017     },
2018
2019     getX : function(el) {
2020         return this.getXY(el)[0];
2021     },
2022
2023     getXY : function(el) {
2024         var p, pe, b, scroll, bd = document.body;
2025         el = Roo.getDom(el);
2026         var fly = Roo.lib.AnimBase.fly;
2027         if (el.getBoundingClientRect) {
2028             b = el.getBoundingClientRect();
2029             scroll = fly(document).getScroll();
2030             return [b.left + scroll.left, b.top + scroll.top];
2031         }
2032         var x = 0, y = 0;
2033
2034         p = el;
2035
2036         var hasAbsolute = fly(el).getStyle("position") == "absolute";
2037
2038         while (p) {
2039
2040             x += p.offsetLeft;
2041             y += p.offsetTop;
2042
2043             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
2044                 hasAbsolute = true;
2045             }
2046
2047             if (Roo.isGecko) {
2048                 pe = fly(p);
2049
2050                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
2051                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
2052
2053
2054                 x += bl;
2055                 y += bt;
2056
2057
2058                 if (p != el && pe.getStyle('overflow') != 'visible') {
2059                     x += bl;
2060                     y += bt;
2061                 }
2062             }
2063             p = p.offsetParent;
2064         }
2065
2066         if (Roo.isSafari && hasAbsolute) {
2067             x -= bd.offsetLeft;
2068             y -= bd.offsetTop;
2069         }
2070
2071         if (Roo.isGecko && !hasAbsolute) {
2072             var dbd = fly(bd);
2073             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
2074             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
2075         }
2076
2077         p = el.parentNode;
2078         while (p && p != bd) {
2079             if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
2080                 x -= p.scrollLeft;
2081                 y -= p.scrollTop;
2082             }
2083             p = p.parentNode;
2084         }
2085         return [x, y];
2086     },
2087  
2088   
2089
2090
2091     setXY : function(el, xy) {
2092         el = Roo.fly(el, '_setXY');
2093         el.position();
2094         var pts = el.translatePoints(xy);
2095         if (xy[0] !== false) {
2096             el.dom.style.left = pts.left + "px";
2097         }
2098         if (xy[1] !== false) {
2099             el.dom.style.top = pts.top + "px";
2100         }
2101     },
2102
2103     setX : function(el, x) {
2104         this.setXY(el, [x, false]);
2105     },
2106
2107     setY : function(el, y) {
2108         this.setXY(el, [false, y]);
2109     }
2110 };
2111 /*
2112  * Portions of this file are based on pieces of Yahoo User Interface Library
2113  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2114  * YUI licensed under the BSD License:
2115  * http://developer.yahoo.net/yui/license.txt
2116  * <script type="text/javascript">
2117  *
2118  */
2119
2120 Roo.lib.Event = function() {
2121     var loadComplete = false;
2122     var listeners = [];
2123     var unloadListeners = [];
2124     var retryCount = 0;
2125     var onAvailStack = [];
2126     var counter = 0;
2127     var lastError = null;
2128
2129     return {
2130         POLL_RETRYS: 200,
2131         POLL_INTERVAL: 20,
2132         EL: 0,
2133         TYPE: 1,
2134         FN: 2,
2135         WFN: 3,
2136         OBJ: 3,
2137         ADJ_SCOPE: 4,
2138         _interval: null,
2139
2140         startInterval: function() {
2141             if (!this._interval) {
2142                 var self = this;
2143                 var callback = function() {
2144                     self._tryPreloadAttach();
2145                 };
2146                 this._interval = setInterval(callback, this.POLL_INTERVAL);
2147
2148             }
2149         },
2150
2151         onAvailable: function(p_id, p_fn, p_obj, p_override) {
2152             onAvailStack.push({ id:         p_id,
2153                 fn:         p_fn,
2154                 obj:        p_obj,
2155                 override:   p_override,
2156                 checkReady: false    });
2157
2158             retryCount = this.POLL_RETRYS;
2159             this.startInterval();
2160         },
2161
2162
2163         addListener: function(el, eventName, fn) {
2164             el = Roo.getDom(el);
2165             if (!el || !fn) {
2166                 return false;
2167             }
2168
2169             if ("unload" == eventName) {
2170                 unloadListeners[unloadListeners.length] =
2171                 [el, eventName, fn];
2172                 return true;
2173             }
2174
2175             var wrappedFn = function(e) {
2176                 return fn(Roo.lib.Event.getEvent(e));
2177             };
2178
2179             var li = [el, eventName, fn, wrappedFn];
2180
2181             var index = listeners.length;
2182             listeners[index] = li;
2183
2184             this.doAdd(el, eventName, wrappedFn, false);
2185             return true;
2186
2187         },
2188
2189
2190         removeListener: function(el, eventName, fn) {
2191             var i, len;
2192
2193             el = Roo.getDom(el);
2194
2195             if(!fn) {
2196                 return this.purgeElement(el, false, eventName);
2197             }
2198
2199
2200             if ("unload" == eventName) {
2201
2202                 for (i = 0,len = unloadListeners.length; i < len; i++) {
2203                     var li = unloadListeners[i];
2204                     if (li &&
2205                         li[0] == el &&
2206                         li[1] == eventName &&
2207                         li[2] == fn) {
2208                         unloadListeners.splice(i, 1);
2209                         return true;
2210                     }
2211                 }
2212
2213                 return false;
2214             }
2215
2216             var cacheItem = null;
2217
2218
2219             var index = arguments[3];
2220
2221             if ("undefined" == typeof index) {
2222                 index = this._getCacheIndex(el, eventName, fn);
2223             }
2224
2225             if (index >= 0) {
2226                 cacheItem = listeners[index];
2227             }
2228
2229             if (!el || !cacheItem) {
2230                 return false;
2231             }
2232
2233             this.doRemove(el, eventName, cacheItem[this.WFN], false);
2234
2235             delete listeners[index][this.WFN];
2236             delete listeners[index][this.FN];
2237             listeners.splice(index, 1);
2238
2239             return true;
2240
2241         },
2242
2243
2244         getTarget: function(ev, resolveTextNode) {
2245             ev = ev.browserEvent || ev;
2246             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2247             var t = ev.target || ev.srcElement;
2248             return this.resolveTextNode(t);
2249         },
2250
2251
2252         resolveTextNode: function(node) {
2253             if (Roo.isSafari && node && 3 == node.nodeType) {
2254                 return node.parentNode;
2255             } else {
2256                 return node;
2257             }
2258         },
2259
2260
2261         getPageX: function(ev) {
2262             ev = ev.browserEvent || ev;
2263             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2264             var x = ev.pageX;
2265             if (!x && 0 !== x) {
2266                 x = ev.clientX || 0;
2267
2268                 if (Roo.isIE) {
2269                     x += this.getScroll()[1];
2270                 }
2271             }
2272
2273             return x;
2274         },
2275
2276
2277         getPageY: function(ev) {
2278             ev = ev.browserEvent || ev;
2279             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2280             var y = ev.pageY;
2281             if (!y && 0 !== y) {
2282                 y = ev.clientY || 0;
2283
2284                 if (Roo.isIE) {
2285                     y += this.getScroll()[0];
2286                 }
2287             }
2288
2289
2290             return y;
2291         },
2292
2293
2294         getXY: function(ev) {
2295             ev = ev.browserEvent || ev;
2296             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2297             return [this.getPageX(ev), this.getPageY(ev)];
2298         },
2299
2300
2301         getRelatedTarget: function(ev) {
2302             ev = ev.browserEvent || ev;
2303             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2304             var t = ev.relatedTarget;
2305             if (!t) {
2306                 if (ev.type == "mouseout") {
2307                     t = ev.toElement;
2308                 } else if (ev.type == "mouseover") {
2309                     t = ev.fromElement;
2310                 }
2311             }
2312
2313             return this.resolveTextNode(t);
2314         },
2315
2316
2317         getTime: function(ev) {
2318             ev = ev.browserEvent || ev;
2319             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2320             if (!ev.time) {
2321                 var t = new Date().getTime();
2322                 try {
2323                     ev.time = t;
2324                 } catch(ex) {
2325                     this.lastError = ex;
2326                     return t;
2327                 }
2328             }
2329
2330             return ev.time;
2331         },
2332
2333
2334         stopEvent: function(ev) {
2335             this.stopPropagation(ev);
2336             this.preventDefault(ev);
2337         },
2338
2339
2340         stopPropagation: function(ev) {
2341             ev = ev.browserEvent || ev;
2342             if (ev.stopPropagation) {
2343                 ev.stopPropagation();
2344             } else {
2345                 ev.cancelBubble = true;
2346             }
2347         },
2348
2349
2350         preventDefault: function(ev) {
2351             ev = ev.browserEvent || ev;
2352             if(ev.preventDefault) {
2353                 ev.preventDefault();
2354             } else {
2355                 ev.returnValue = false;
2356             }
2357         },
2358
2359
2360         getEvent: function(e) {
2361             var ev = e || window.event;
2362             if (!ev) {
2363                 var c = this.getEvent.caller;
2364                 while (c) {
2365                     ev = c.arguments[0];
2366                     if (ev && Event == ev.constructor) {
2367                         break;
2368                     }
2369                     c = c.caller;
2370                 }
2371             }
2372             return ev;
2373         },
2374
2375
2376         getCharCode: function(ev) {
2377             ev = ev.browserEvent || ev;
2378             return ev.charCode || ev.keyCode || 0;
2379         },
2380
2381
2382         _getCacheIndex: function(el, eventName, fn) {
2383             for (var i = 0,len = listeners.length; i < len; ++i) {
2384                 var li = listeners[i];
2385                 if (li &&
2386                     li[this.FN] == fn &&
2387                     li[this.EL] == el &&
2388                     li[this.TYPE] == eventName) {
2389                     return i;
2390                 }
2391             }
2392
2393             return -1;
2394         },
2395
2396
2397         elCache: {},
2398
2399
2400         getEl: function(id) {
2401             return document.getElementById(id);
2402         },
2403
2404
2405         clearCache: function() {
2406         },
2407
2408
2409         _load: function(e) {
2410             loadComplete = true;
2411             var EU = Roo.lib.Event;
2412
2413
2414             if (Roo.isIE) {
2415                 EU.doRemove(window, "load", EU._load);
2416             }
2417         },
2418
2419
2420         _tryPreloadAttach: function() {
2421
2422             if (this.locked) {
2423                 return false;
2424             }
2425
2426             this.locked = true;
2427
2428
2429             var tryAgain = !loadComplete;
2430             if (!tryAgain) {
2431                 tryAgain = (retryCount > 0);
2432             }
2433
2434
2435             var notAvail = [];
2436             for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2437                 var item = onAvailStack[i];
2438                 if (item) {
2439                     var el = this.getEl(item.id);
2440
2441                     if (el) {
2442                         if (!item.checkReady ||
2443                             loadComplete ||
2444                             el.nextSibling ||
2445                             (document && document.body)) {
2446
2447                             var scope = el;
2448                             if (item.override) {
2449                                 if (item.override === true) {
2450                                     scope = item.obj;
2451                                 } else {
2452                                     scope = item.override;
2453                                 }
2454                             }
2455                             item.fn.call(scope, item.obj);
2456                             onAvailStack[i] = null;
2457                         }
2458                     } else {
2459                         notAvail.push(item);
2460                     }
2461                 }
2462             }
2463
2464             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2465
2466             if (tryAgain) {
2467
2468                 this.startInterval();
2469             } else {
2470                 clearInterval(this._interval);
2471                 this._interval = null;
2472             }
2473
2474             this.locked = false;
2475
2476             return true;
2477
2478         },
2479
2480
2481         purgeElement: function(el, recurse, eventName) {
2482             var elListeners = this.getListeners(el, eventName);
2483             if (elListeners) {
2484                 for (var i = 0,len = elListeners.length; i < len; ++i) {
2485                     var l = elListeners[i];
2486                     this.removeListener(el, l.type, l.fn);
2487                 }
2488             }
2489
2490             if (recurse && el && el.childNodes) {
2491                 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2492                     this.purgeElement(el.childNodes[i], recurse, eventName);
2493                 }
2494             }
2495         },
2496
2497
2498         getListeners: function(el, eventName) {
2499             var results = [], searchLists;
2500             if (!eventName) {
2501                 searchLists = [listeners, unloadListeners];
2502             } else if (eventName == "unload") {
2503                 searchLists = [unloadListeners];
2504             } else {
2505                 searchLists = [listeners];
2506             }
2507
2508             for (var j = 0; j < searchLists.length; ++j) {
2509                 var searchList = searchLists[j];
2510                 if (searchList && searchList.length > 0) {
2511                     for (var i = 0,len = searchList.length; i < len; ++i) {
2512                         var l = searchList[i];
2513                         if (l && l[this.EL] === el &&
2514                             (!eventName || eventName === l[this.TYPE])) {
2515                             results.push({
2516                                 type:   l[this.TYPE],
2517                                 fn:     l[this.FN],
2518                                 obj:    l[this.OBJ],
2519                                 adjust: l[this.ADJ_SCOPE],
2520                                 index:  i
2521                             });
2522                         }
2523                     }
2524                 }
2525             }
2526
2527             return (results.length) ? results : null;
2528         },
2529
2530
2531         _unload: function(e) {
2532
2533             var EU = Roo.lib.Event, i, j, l, len, index;
2534
2535             for (i = 0,len = unloadListeners.length; i < len; ++i) {
2536                 l = unloadListeners[i];
2537                 if (l) {
2538                     var scope = window;
2539                     if (l[EU.ADJ_SCOPE]) {
2540                         if (l[EU.ADJ_SCOPE] === true) {
2541                             scope = l[EU.OBJ];
2542                         } else {
2543                             scope = l[EU.ADJ_SCOPE];
2544                         }
2545                     }
2546                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2547                     unloadListeners[i] = null;
2548                     l = null;
2549                     scope = null;
2550                 }
2551             }
2552
2553             unloadListeners = null;
2554
2555             if (listeners && listeners.length > 0) {
2556                 j = listeners.length;
2557                 while (j) {
2558                     index = j - 1;
2559                     l = listeners[index];
2560                     if (l) {
2561                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2562                                 l[EU.FN], index);
2563                     }
2564                     j = j - 1;
2565                 }
2566                 l = null;
2567
2568                 EU.clearCache();
2569             }
2570
2571             EU.doRemove(window, "unload", EU._unload);
2572
2573         },
2574
2575
2576         getScroll: function() {
2577             var dd = document.documentElement, db = document.body;
2578             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2579                 return [dd.scrollTop, dd.scrollLeft];
2580             } else if (db) {
2581                 return [db.scrollTop, db.scrollLeft];
2582             } else {
2583                 return [0, 0];
2584             }
2585         },
2586
2587
2588         doAdd: function () {
2589             if (window.addEventListener) {
2590                 return function(el, eventName, fn, capture) {
2591                     el.addEventListener(eventName, fn, (capture));
2592                 };
2593             } else if (window.attachEvent) {
2594                 return function(el, eventName, fn, capture) {
2595                     el.attachEvent("on" + eventName, fn);
2596                 };
2597             } else {
2598                 return function() {
2599                 };
2600             }
2601         }(),
2602
2603
2604         doRemove: function() {
2605             if (window.removeEventListener) {
2606                 return function (el, eventName, fn, capture) {
2607                     el.removeEventListener(eventName, fn, (capture));
2608                 };
2609             } else if (window.detachEvent) {
2610                 return function (el, eventName, fn) {
2611                     el.detachEvent("on" + eventName, fn);
2612                 };
2613             } else {
2614                 return function() {
2615                 };
2616             }
2617         }()
2618     };
2619     
2620 }();
2621 (function() {     
2622    
2623     var E = Roo.lib.Event;
2624     E.on = E.addListener;
2625     E.un = E.removeListener;
2626
2627     if (document && document.body) {
2628         E._load();
2629     } else {
2630         E.doAdd(window, "load", E._load);
2631     }
2632     E.doAdd(window, "unload", E._unload);
2633     E._tryPreloadAttach();
2634 })();
2635
2636  
2637
2638 (function() {
2639     /**
2640      * @class Roo.lib.Ajax
2641      *
2642      * provide a simple Ajax request utility functions
2643      * 
2644      * Portions of this file are based on pieces of Yahoo User Interface Library
2645     * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2646     * YUI licensed under the BSD License:
2647     * http://developer.yahoo.net/yui/license.txt
2648     * <script type="text/javascript">
2649     *
2650      *
2651      */
2652     Roo.lib.Ajax = {
2653         /**
2654          * @static 
2655          */
2656         request : function(method, uri, cb, data, options) {
2657             if(options){
2658                 var hs = options.headers;
2659                 if(hs){
2660                     for(var h in hs){
2661                         if(hs.hasOwnProperty(h)){
2662                             this.initHeader(h, hs[h], false);
2663                         }
2664                     }
2665                 }
2666                 if(options.xmlData){
2667                     this.initHeader('Content-Type', 'text/xml', false);
2668                     method = 'POST';
2669                     data = options.xmlData;
2670                 }
2671             }
2672
2673             return this.asyncRequest(method, uri, cb, data);
2674         },
2675         /**
2676          * serialize a form
2677          *
2678          * @static
2679          * @param {DomForm} form element
2680          * @return {String} urlencode form output.
2681          */
2682         serializeForm : function(form) {
2683             if(typeof form == 'string') {
2684                 form = (document.getElementById(form) || document.forms[form]);
2685             }
2686
2687             var el, name, val, disabled, data = '', hasSubmit = false;
2688             for (var i = 0; i < form.elements.length; i++) {
2689                 el = form.elements[i];
2690                 disabled = form.elements[i].disabled;
2691                 name = form.elements[i].name;
2692                 val = form.elements[i].value;
2693
2694                 if (!disabled && name){
2695                     switch (el.type)
2696                             {
2697                         case 'select-one':
2698                         case 'select-multiple':
2699                             for (var j = 0; j < el.options.length; j++) {
2700                                 if (el.options[j].selected) {
2701                                     if (Roo.isIE) {
2702                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2703                                     }
2704                                     else {
2705                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2706                                     }
2707                                 }
2708                             }
2709                             break;
2710                         case 'radio':
2711                         case 'checkbox':
2712                             if (el.checked) {
2713                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2714                             }
2715                             break;
2716                         case 'file':
2717
2718                         case undefined:
2719
2720                         case 'reset':
2721
2722                         case 'button':
2723
2724                             break;
2725                         case 'submit':
2726                             if(hasSubmit == false) {
2727                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2728                                 hasSubmit = true;
2729                             }
2730                             break;
2731                         default:
2732                             data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2733                             break;
2734                     }
2735                 }
2736             }
2737             data = data.substr(0, data.length - 1);
2738             return data;
2739         },
2740
2741         headers:{},
2742
2743         hasHeaders:false,
2744
2745         useDefaultHeader:true,
2746
2747         defaultPostHeader:'application/x-www-form-urlencoded',
2748
2749         useDefaultXhrHeader:true,
2750
2751         defaultXhrHeader:'XMLHttpRequest',
2752
2753         hasDefaultHeaders:true,
2754
2755         defaultHeaders:{},
2756
2757         poll:{},
2758
2759         timeout:{},
2760
2761         pollInterval:50,
2762
2763         transactionId:0,
2764
2765         setProgId:function(id)
2766         {
2767             this.activeX.unshift(id);
2768         },
2769
2770         setDefaultPostHeader:function(b)
2771         {
2772             this.useDefaultHeader = b;
2773         },
2774
2775         setDefaultXhrHeader:function(b)
2776         {
2777             this.useDefaultXhrHeader = b;
2778         },
2779
2780         setPollingInterval:function(i)
2781         {
2782             if (typeof i == 'number' && isFinite(i)) {
2783                 this.pollInterval = i;
2784             }
2785         },
2786
2787         createXhrObject:function(transactionId)
2788         {
2789             var obj,http;
2790             try
2791             {
2792
2793                 http = new XMLHttpRequest();
2794
2795                 obj = { conn:http, tId:transactionId };
2796             }
2797             catch(e)
2798             {
2799                 for (var i = 0; i < this.activeX.length; ++i) {
2800                     try
2801                     {
2802
2803                         http = new ActiveXObject(this.activeX[i]);
2804
2805                         obj = { conn:http, tId:transactionId };
2806                         break;
2807                     }
2808                     catch(e) {
2809                     }
2810                 }
2811             }
2812             finally
2813             {
2814                 return obj;
2815             }
2816         },
2817
2818         getConnectionObject:function()
2819         {
2820             var o;
2821             var tId = this.transactionId;
2822
2823             try
2824             {
2825                 o = this.createXhrObject(tId);
2826                 if (o) {
2827                     this.transactionId++;
2828                 }
2829             }
2830             catch(e) {
2831             }
2832             finally
2833             {
2834                 return o;
2835             }
2836         },
2837
2838         asyncRequest:function(method, uri, callback, postData)
2839         {
2840             var o = this.getConnectionObject();
2841
2842             if (!o) {
2843                 return null;
2844             }
2845             else {
2846                 o.conn.open(method, uri, true);
2847
2848                 if (this.useDefaultXhrHeader) {
2849                     if (!this.defaultHeaders['X-Requested-With']) {
2850                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2851                     }
2852                 }
2853
2854                 if(postData && this.useDefaultHeader){
2855                     this.initHeader('Content-Type', this.defaultPostHeader);
2856                 }
2857
2858                  if (this.hasDefaultHeaders || this.hasHeaders) {
2859                     this.setHeader(o);
2860                 }
2861
2862                 this.handleReadyState(o, callback);
2863                 o.conn.send(postData || null);
2864
2865                 return o;
2866             }
2867         },
2868
2869         handleReadyState:function(o, callback)
2870         {
2871             var oConn = this;
2872
2873             if (callback && callback.timeout) {
2874                 
2875                 this.timeout[o.tId] = window.setTimeout(function() {
2876                     oConn.abort(o, callback, true);
2877                 }, callback.timeout);
2878             }
2879
2880             this.poll[o.tId] = window.setInterval(
2881                     function() {
2882                         if (o.conn && o.conn.readyState == 4) {
2883                             window.clearInterval(oConn.poll[o.tId]);
2884                             delete oConn.poll[o.tId];
2885
2886                             if(callback && callback.timeout) {
2887                                 window.clearTimeout(oConn.timeout[o.tId]);
2888                                 delete oConn.timeout[o.tId];
2889                             }
2890
2891                             oConn.handleTransactionResponse(o, callback);
2892                         }
2893                     }
2894                     , this.pollInterval);
2895         },
2896
2897         handleTransactionResponse:function(o, callback, isAbort)
2898         {
2899
2900             if (!callback) {
2901                 this.releaseObject(o);
2902                 return;
2903             }
2904
2905             var httpStatus, responseObject;
2906
2907             try
2908             {
2909                 if (o.conn.status !== undefined && o.conn.status != 0) {
2910                     httpStatus = o.conn.status;
2911                 }
2912                 else {
2913                     httpStatus = 13030;
2914                 }
2915             }
2916             catch(e) {
2917
2918
2919                 httpStatus = 13030;
2920             }
2921
2922             if (httpStatus >= 200 && httpStatus < 300) {
2923                 responseObject = this.createResponseObject(o, callback.argument);
2924                 if (callback.success) {
2925                     if (!callback.scope) {
2926                         callback.success(responseObject);
2927                     }
2928                     else {
2929
2930
2931                         callback.success.apply(callback.scope, [responseObject]);
2932                     }
2933                 }
2934             }
2935             else {
2936                 switch (httpStatus) {
2937
2938                     case 12002:
2939                     case 12029:
2940                     case 12030:
2941                     case 12031:
2942                     case 12152:
2943                     case 13030:
2944                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2945                         if (callback.failure) {
2946                             if (!callback.scope) {
2947                                 callback.failure(responseObject);
2948                             }
2949                             else {
2950                                 callback.failure.apply(callback.scope, [responseObject]);
2951                             }
2952                         }
2953                         break;
2954                     default:
2955                         responseObject = this.createResponseObject(o, callback.argument);
2956                         if (callback.failure) {
2957                             if (!callback.scope) {
2958                                 callback.failure(responseObject);
2959                             }
2960                             else {
2961                                 callback.failure.apply(callback.scope, [responseObject]);
2962                             }
2963                         }
2964                 }
2965             }
2966
2967             this.releaseObject(o);
2968             responseObject = null;
2969         },
2970
2971         createResponseObject:function(o, callbackArg)
2972         {
2973             var obj = {};
2974             var headerObj = {};
2975
2976             try
2977             {
2978                 var headerStr = o.conn.getAllResponseHeaders();
2979                 var header = headerStr.split('\n');
2980                 for (var i = 0; i < header.length; i++) {
2981                     var delimitPos = header[i].indexOf(':');
2982                     if (delimitPos != -1) {
2983                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2984                     }
2985                 }
2986             }
2987             catch(e) {
2988             }
2989
2990             obj.tId = o.tId;
2991             obj.status = o.conn.status;
2992             obj.statusText = o.conn.statusText;
2993             obj.getResponseHeader = headerObj;
2994             obj.getAllResponseHeaders = headerStr;
2995             obj.responseText = o.conn.responseText;
2996             obj.responseXML = o.conn.responseXML;
2997
2998             if (typeof callbackArg !== undefined) {
2999                 obj.argument = callbackArg;
3000             }
3001
3002             return obj;
3003         },
3004
3005         createExceptionObject:function(tId, callbackArg, isAbort)
3006         {
3007             var COMM_CODE = 0;
3008             var COMM_ERROR = 'communication failure';
3009             var ABORT_CODE = -1;
3010             var ABORT_ERROR = 'transaction aborted';
3011
3012             var obj = {};
3013
3014             obj.tId = tId;
3015             if (isAbort) {
3016                 obj.status = ABORT_CODE;
3017                 obj.statusText = ABORT_ERROR;
3018             }
3019             else {
3020                 obj.status = COMM_CODE;
3021                 obj.statusText = COMM_ERROR;
3022             }
3023
3024             if (callbackArg) {
3025                 obj.argument = callbackArg;
3026             }
3027
3028             return obj;
3029         },
3030
3031         initHeader:function(label, value, isDefault)
3032         {
3033             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
3034
3035             if (headerObj[label] === undefined) {
3036                 headerObj[label] = value;
3037             }
3038             else {
3039
3040
3041                 headerObj[label] = value + "," + headerObj[label];
3042             }
3043
3044             if (isDefault) {
3045                 this.hasDefaultHeaders = true;
3046             }
3047             else {
3048                 this.hasHeaders = true;
3049             }
3050         },
3051
3052
3053         setHeader:function(o)
3054         {
3055             if (this.hasDefaultHeaders) {
3056                 for (var prop in this.defaultHeaders) {
3057                     if (this.defaultHeaders.hasOwnProperty(prop)) {
3058                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
3059                     }
3060                 }
3061             }
3062
3063             if (this.hasHeaders) {
3064                 for (var prop in this.headers) {
3065                     if (this.headers.hasOwnProperty(prop)) {
3066                         o.conn.setRequestHeader(prop, this.headers[prop]);
3067                     }
3068                 }
3069                 this.headers = {};
3070                 this.hasHeaders = false;
3071             }
3072         },
3073
3074         resetDefaultHeaders:function() {
3075             delete this.defaultHeaders;
3076             this.defaultHeaders = {};
3077             this.hasDefaultHeaders = false;
3078         },
3079
3080         abort:function(o, callback, isTimeout)
3081         {
3082             if(this.isCallInProgress(o)) {
3083                 o.conn.abort();
3084                 window.clearInterval(this.poll[o.tId]);
3085                 delete this.poll[o.tId];
3086                 if (isTimeout) {
3087                     delete this.timeout[o.tId];
3088                 }
3089
3090                 this.handleTransactionResponse(o, callback, true);
3091
3092                 return true;
3093             }
3094             else {
3095                 return false;
3096             }
3097         },
3098
3099
3100         isCallInProgress:function(o)
3101         {
3102             if (o && o.conn) {
3103                 return o.conn.readyState != 4 && o.conn.readyState != 0;
3104             }
3105             else {
3106
3107                 return false;
3108             }
3109         },
3110
3111
3112         releaseObject:function(o)
3113         {
3114
3115             o.conn = null;
3116
3117             o = null;
3118         },
3119
3120         activeX:[
3121         'MSXML2.XMLHTTP.3.0',
3122         'MSXML2.XMLHTTP',
3123         'Microsoft.XMLHTTP'
3124         ]
3125
3126
3127     };
3128 })();/*
3129  * Portions of this file are based on pieces of Yahoo User Interface Library
3130  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3131  * YUI licensed under the BSD License:
3132  * http://developer.yahoo.net/yui/license.txt
3133  * <script type="text/javascript">
3134  *
3135  */
3136
3137 Roo.lib.Region = function(t, r, b, l) {
3138     this.top = t;
3139     this[1] = t;
3140     this.right = r;
3141     this.bottom = b;
3142     this.left = l;
3143     this[0] = l;
3144 };
3145
3146
3147 Roo.lib.Region.prototype = {
3148     contains : function(region) {
3149         return ( region.left >= this.left &&
3150                  region.right <= this.right &&
3151                  region.top >= this.top &&
3152                  region.bottom <= this.bottom    );
3153
3154     },
3155
3156     getArea : function() {
3157         return ( (this.bottom - this.top) * (this.right - this.left) );
3158     },
3159
3160     intersect : function(region) {
3161         var t = Math.max(this.top, region.top);
3162         var r = Math.min(this.right, region.right);
3163         var b = Math.min(this.bottom, region.bottom);
3164         var l = Math.max(this.left, region.left);
3165
3166         if (b >= t && r >= l) {
3167             return new Roo.lib.Region(t, r, b, l);
3168         } else {
3169             return null;
3170         }
3171     },
3172     union : function(region) {
3173         var t = Math.min(this.top, region.top);
3174         var r = Math.max(this.right, region.right);
3175         var b = Math.max(this.bottom, region.bottom);
3176         var l = Math.min(this.left, region.left);
3177
3178         return new Roo.lib.Region(t, r, b, l);
3179     },
3180
3181     adjust : function(t, l, b, r) {
3182         this.top += t;
3183         this.left += l;
3184         this.right += r;
3185         this.bottom += b;
3186         return this;
3187     }
3188 };
3189
3190 Roo.lib.Region.getRegion = function(el) {
3191     var p = Roo.lib.Dom.getXY(el);
3192
3193     var t = p[1];
3194     var r = p[0] + el.offsetWidth;
3195     var b = p[1] + el.offsetHeight;
3196     var l = p[0];
3197
3198     return new Roo.lib.Region(t, r, b, l);
3199 };
3200 /*
3201  * Portions of this file are based on pieces of Yahoo User Interface Library
3202  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3203  * YUI licensed under the BSD License:
3204  * http://developer.yahoo.net/yui/license.txt
3205  * <script type="text/javascript">
3206  *
3207  */
3208 //@@dep Roo.lib.Region
3209
3210
3211 Roo.lib.Point = function(x, y) {
3212     if (x instanceof Array) {
3213         y = x[1];
3214         x = x[0];
3215     }
3216     this.x = this.right = this.left = this[0] = x;
3217     this.y = this.top = this.bottom = this[1] = y;
3218 };
3219
3220 Roo.lib.Point.prototype = new Roo.lib.Region();
3221 /*
3222  * Portions of this file are based on pieces of Yahoo User Interface Library
3223  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3224  * YUI licensed under the BSD License:
3225  * http://developer.yahoo.net/yui/license.txt
3226  * <script type="text/javascript">
3227  *
3228  */
3229  
3230 (function() {   
3231
3232     Roo.lib.Anim = {
3233         scroll : function(el, args, duration, easing, cb, scope) {
3234             this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3235         },
3236
3237         motion : function(el, args, duration, easing, cb, scope) {
3238             this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3239         },
3240
3241         color : function(el, args, duration, easing, cb, scope) {
3242             this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3243         },
3244
3245         run : function(el, args, duration, easing, cb, scope, type) {
3246             type = type || Roo.lib.AnimBase;
3247             if (typeof easing == "string") {
3248                 easing = Roo.lib.Easing[easing];
3249             }
3250             var anim = new type(el, args, duration, easing);
3251             anim.animateX(function() {
3252                 Roo.callback(cb, scope);
3253             });
3254             return anim;
3255         }
3256     };
3257 })();/*
3258  * Portions of this file are based on pieces of Yahoo User Interface Library
3259  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3260  * YUI licensed under the BSD License:
3261  * http://developer.yahoo.net/yui/license.txt
3262  * <script type="text/javascript">
3263  *
3264  */
3265
3266 (function() {    
3267     var libFlyweight;
3268     
3269     function fly(el) {
3270         if (!libFlyweight) {
3271             libFlyweight = new Roo.Element.Flyweight();
3272         }
3273         libFlyweight.dom = el;
3274         return libFlyweight;
3275     }
3276
3277     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3278     
3279    
3280     
3281     Roo.lib.AnimBase = function(el, attributes, duration, method) {
3282         if (el) {
3283             this.init(el, attributes, duration, method);
3284         }
3285     };
3286
3287     Roo.lib.AnimBase.fly = fly;
3288     
3289     
3290     
3291     Roo.lib.AnimBase.prototype = {
3292
3293         toString: function() {
3294             var el = this.getEl();
3295             var id = el.id || el.tagName;
3296             return ("Anim " + id);
3297         },
3298
3299         patterns: {
3300             noNegatives:        /width|height|opacity|padding/i,
3301             offsetAttribute:  /^((width|height)|(top|left))$/,
3302             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
3303             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3304         },
3305
3306
3307         doMethod: function(attr, start, end) {
3308             return this.method(this.currentFrame, start, end - start, this.totalFrames);
3309         },
3310
3311
3312         setAttribute: function(attr, val, unit) {
3313             if (this.patterns.noNegatives.test(attr)) {
3314                 val = (val > 0) ? val : 0;
3315             }
3316
3317             Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3318         },
3319
3320
3321         getAttribute: function(attr) {
3322             var el = this.getEl();
3323             var val = fly(el).getStyle(attr);
3324
3325             if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3326                 return parseFloat(val);
3327             }
3328
3329             var a = this.patterns.offsetAttribute.exec(attr) || [];
3330             var pos = !!( a[3] );
3331             var box = !!( a[2] );
3332
3333
3334             if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3335                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3336             } else {
3337                 val = 0;
3338             }
3339
3340             return val;
3341         },
3342
3343
3344         getDefaultUnit: function(attr) {
3345             if (this.patterns.defaultUnit.test(attr)) {
3346                 return 'px';
3347             }
3348
3349             return '';
3350         },
3351
3352         animateX : function(callback, scope) {
3353             var f = function() {
3354                 this.onComplete.removeListener(f);
3355                 if (typeof callback == "function") {
3356                     callback.call(scope || this, this);
3357                 }
3358             };
3359             this.onComplete.addListener(f, this);
3360             this.animate();
3361         },
3362
3363
3364         setRuntimeAttribute: function(attr) {
3365             var start;
3366             var end;
3367             var attributes = this.attributes;
3368
3369             this.runtimeAttributes[attr] = {};
3370
3371             var isset = function(prop) {
3372                 return (typeof prop !== 'undefined');
3373             };
3374
3375             if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3376                 return false;
3377             }
3378
3379             start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3380
3381
3382             if (isset(attributes[attr]['to'])) {
3383                 end = attributes[attr]['to'];
3384             } else if (isset(attributes[attr]['by'])) {
3385                 if (start.constructor == Array) {
3386                     end = [];
3387                     for (var i = 0, len = start.length; i < len; ++i) {
3388                         end[i] = start[i] + attributes[attr]['by'][i];
3389                     }
3390                 } else {
3391                     end = start + attributes[attr]['by'];
3392                 }
3393             }
3394
3395             this.runtimeAttributes[attr].start = start;
3396             this.runtimeAttributes[attr].end = end;
3397
3398
3399             this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3400         },
3401
3402
3403         init: function(el, attributes, duration, method) {
3404
3405             var isAnimated = false;
3406
3407
3408             var startTime = null;
3409
3410
3411             var actualFrames = 0;
3412
3413
3414             el = Roo.getDom(el);
3415
3416
3417             this.attributes = attributes || {};
3418
3419
3420             this.duration = duration || 1;
3421
3422
3423             this.method = method || Roo.lib.Easing.easeNone;
3424
3425
3426             this.useSeconds = true;
3427
3428
3429             this.currentFrame = 0;
3430
3431
3432             this.totalFrames = Roo.lib.AnimMgr.fps;
3433
3434
3435             this.getEl = function() {
3436                 return el;
3437             };
3438
3439
3440             this.isAnimated = function() {
3441                 return isAnimated;
3442             };
3443
3444
3445             this.getStartTime = function() {
3446                 return startTime;
3447             };
3448
3449             this.runtimeAttributes = {};
3450
3451
3452             this.animate = function() {
3453                 if (this.isAnimated()) {
3454                     return false;
3455                 }
3456
3457                 this.currentFrame = 0;
3458
3459                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3460
3461                 Roo.lib.AnimMgr.registerElement(this);
3462             };
3463
3464
3465             this.stop = function(finish) {
3466                 if (finish) {
3467                     this.currentFrame = this.totalFrames;
3468                     this._onTween.fire();
3469                 }
3470                 Roo.lib.AnimMgr.stop(this);
3471             };
3472
3473             var onStart = function() {
3474                 this.onStart.fire();
3475
3476                 this.runtimeAttributes = {};
3477                 for (var attr in this.attributes) {
3478                     this.setRuntimeAttribute(attr);
3479                 }
3480
3481                 isAnimated = true;
3482                 actualFrames = 0;
3483                 startTime = new Date();
3484             };
3485
3486
3487             var onTween = function() {
3488                 var data = {
3489                     duration: new Date() - this.getStartTime(),
3490                     currentFrame: this.currentFrame
3491                 };
3492
3493                 data.toString = function() {
3494                     return (
3495                             'duration: ' + data.duration +
3496                             ', currentFrame: ' + data.currentFrame
3497                             );
3498                 };
3499
3500                 this.onTween.fire(data);
3501
3502                 var runtimeAttributes = this.runtimeAttributes;
3503
3504                 for (var attr in runtimeAttributes) {
3505                     this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3506                 }
3507
3508                 actualFrames += 1;
3509             };
3510
3511             var onComplete = function() {
3512                 var actual_duration = (new Date() - startTime) / 1000 ;
3513
3514                 var data = {
3515                     duration: actual_duration,
3516                     frames: actualFrames,
3517                     fps: actualFrames / actual_duration
3518                 };
3519
3520                 data.toString = function() {
3521                     return (
3522                             'duration: ' + data.duration +
3523                             ', frames: ' + data.frames +
3524                             ', fps: ' + data.fps
3525                             );
3526                 };
3527
3528                 isAnimated = false;
3529                 actualFrames = 0;
3530                 this.onComplete.fire(data);
3531             };
3532
3533
3534             this._onStart = new Roo.util.Event(this);
3535             this.onStart = new Roo.util.Event(this);
3536             this.onTween = new Roo.util.Event(this);
3537             this._onTween = new Roo.util.Event(this);
3538             this.onComplete = new Roo.util.Event(this);
3539             this._onComplete = new Roo.util.Event(this);
3540             this._onStart.addListener(onStart);
3541             this._onTween.addListener(onTween);
3542             this._onComplete.addListener(onComplete);
3543         }
3544     };
3545 })();
3546 /*
3547  * Portions of this file are based on pieces of Yahoo User Interface Library
3548  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3549  * YUI licensed under the BSD License:
3550  * http://developer.yahoo.net/yui/license.txt
3551  * <script type="text/javascript">
3552  *
3553  */
3554
3555 Roo.lib.AnimMgr = new function() {
3556
3557     var thread = null;
3558
3559
3560     var queue = [];
3561
3562
3563     var tweenCount = 0;
3564
3565
3566     this.fps = 1000;
3567
3568
3569     this.delay = 1;
3570
3571
3572     this.registerElement = function(tween) {
3573         queue[queue.length] = tween;
3574         tweenCount += 1;
3575         tween._onStart.fire();
3576         this.start();
3577     };
3578
3579
3580     this.unRegister = function(tween, index) {
3581         tween._onComplete.fire();
3582         index = index || getIndex(tween);
3583         if (index != -1) {
3584             queue.splice(index, 1);
3585         }
3586
3587         tweenCount -= 1;
3588         if (tweenCount <= 0) {
3589             this.stop();
3590         }
3591     };
3592
3593
3594     this.start = function() {
3595         if (thread === null) {
3596             thread = setInterval(this.run, this.delay);
3597         }
3598     };
3599
3600
3601     this.stop = function(tween) {
3602         if (!tween) {
3603             clearInterval(thread);
3604
3605             for (var i = 0, len = queue.length; i < len; ++i) {
3606                 if (queue[0].isAnimated()) {
3607                     this.unRegister(queue[0], 0);
3608                 }
3609             }
3610
3611             queue = [];
3612             thread = null;
3613             tweenCount = 0;
3614         }
3615         else {
3616             this.unRegister(tween);
3617         }
3618     };
3619
3620
3621     this.run = function() {
3622         for (var i = 0, len = queue.length; i < len; ++i) {
3623             var tween = queue[i];
3624             if (!tween || !tween.isAnimated()) {
3625                 continue;
3626             }
3627
3628             if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3629             {
3630                 tween.currentFrame += 1;
3631
3632                 if (tween.useSeconds) {
3633                     correctFrame(tween);
3634                 }
3635                 tween._onTween.fire();
3636             }
3637             else {
3638                 Roo.lib.AnimMgr.stop(tween, i);
3639             }
3640         }
3641     };
3642
3643     var getIndex = function(anim) {
3644         for (var i = 0, len = queue.length; i < len; ++i) {
3645             if (queue[i] == anim) {
3646                 return i;
3647             }
3648         }
3649         return -1;
3650     };
3651
3652
3653     var correctFrame = function(tween) {
3654         var frames = tween.totalFrames;
3655         var frame = tween.currentFrame;
3656         var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3657         var elapsed = (new Date() - tween.getStartTime());
3658         var tweak = 0;
3659
3660         if (elapsed < tween.duration * 1000) {
3661             tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3662         } else {
3663             tweak = frames - (frame + 1);
3664         }
3665         if (tweak > 0 && isFinite(tweak)) {
3666             if (tween.currentFrame + tweak >= frames) {
3667                 tweak = frames - (frame + 1);
3668             }
3669
3670             tween.currentFrame += tweak;
3671         }
3672     };
3673 };
3674
3675     /*
3676  * Portions of this file are based on pieces of Yahoo User Interface Library
3677  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3678  * YUI licensed under the BSD License:
3679  * http://developer.yahoo.net/yui/license.txt
3680  * <script type="text/javascript">
3681  *
3682  */
3683 Roo.lib.Bezier = new function() {
3684
3685         this.getPosition = function(points, t) {
3686             var n = points.length;
3687             var tmp = [];
3688
3689             for (var i = 0; i < n; ++i) {
3690                 tmp[i] = [points[i][0], points[i][1]];
3691             }
3692
3693             for (var j = 1; j < n; ++j) {
3694                 for (i = 0; i < n - j; ++i) {
3695                     tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3696                     tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3697                 }
3698             }
3699
3700             return [ tmp[0][0], tmp[0][1] ];
3701
3702         };
3703     }; 
3704
3705 /**
3706  * @class Roo.lib.Color
3707  * @constructor
3708  * An abstract Color implementation. Concrete Color implementations should use
3709  * an instance of this function as their prototype, and implement the getRGB and
3710  * getHSL functions. getRGB should return an object representing the RGB
3711  * components of this Color, with the red, green, and blue components in the
3712  * range [0,255] and the alpha component in the range [0,100]. getHSL should
3713  * return an object representing the HSL components of this Color, with the hue
3714  * component in the range [0,360), the saturation and lightness components in
3715  * the range [0,100], and the alpha component in the range [0,1].
3716  *
3717  *
3718  * Color.js
3719  *
3720  * Functions for Color handling and processing.
3721  *
3722  * http://www.safalra.com/web-design/javascript/Color-handling-and-processing/
3723  *
3724  * The author of this program, Safalra (Stephen Morley), irrevocably releases all
3725  * rights to this program, with the intention of it becoming part of the public
3726  * domain. Because this program is released into the public domain, it comes with
3727  * no warranty either expressed or implied, to the extent permitted by law.
3728  * 
3729  * For more free and public domain JavaScript code by the same author, visit:
3730  * http://www.safalra.com/web-design/javascript/
3731  * 
3732  */
3733 Roo.lib.Color = function() { }
3734
3735
3736 Roo.apply(Roo.lib.Color.prototype, {
3737   
3738   rgb : null,
3739   hsv : null,
3740   hsl : null,
3741   
3742   /**
3743    * getIntegerRGB
3744    * @return {Object} an object representing the RGBA components of this Color. The red,
3745    * green, and blue components are converted to integers in the range [0,255].
3746    * The alpha is a value in the range [0,1].
3747    */
3748   getIntegerRGB : function(){
3749
3750     // get the RGB components of this Color
3751     var rgb = this.getRGB();
3752
3753     // return the integer components
3754     return {
3755       'r' : Math.round(rgb.r),
3756       'g' : Math.round(rgb.g),
3757       'b' : Math.round(rgb.b),
3758       'a' : rgb.a
3759     };
3760
3761   },
3762
3763   /**
3764    * getPercentageRGB
3765    * @return {Object} an object representing the RGBA components of this Color. The red,
3766    * green, and blue components are converted to numbers in the range [0,100].
3767    * The alpha is a value in the range [0,1].
3768    */
3769   getPercentageRGB : function(){
3770
3771     // get the RGB components of this Color
3772     var rgb = this.getRGB();
3773
3774     // return the percentage components
3775     return {
3776       'r' : 100 * rgb.r / 255,
3777       'g' : 100 * rgb.g / 255,
3778       'b' : 100 * rgb.b / 255,
3779       'a' : rgb.a
3780     };
3781
3782   },
3783
3784   /**
3785    * getCSSHexadecimalRGB
3786    * @return {String} a string representing this Color as a CSS hexadecimal RGB Color
3787    * value - that is, a string of the form #RRGGBB where each of RR, GG, and BB
3788    * are two-digit hexadecimal numbers.
3789    */
3790   getCSSHexadecimalRGB : function()
3791   {
3792
3793     // get the integer RGB components
3794     var rgb = this.getIntegerRGB();
3795
3796     // determine the hexadecimal equivalents
3797     var r16 = rgb.r.toString(16);
3798     var g16 = rgb.g.toString(16);
3799     var b16 = rgb.b.toString(16);
3800
3801     // return the CSS RGB Color value
3802     return '#'
3803         + (r16.length == 2 ? r16 : '0' + r16)
3804         + (g16.length == 2 ? g16 : '0' + g16)
3805         + (b16.length == 2 ? b16 : '0' + b16);
3806
3807   },
3808
3809   /**
3810    * getCSSIntegerRGB
3811    * @return {String} a string representing this Color as a CSS integer RGB Color
3812    * value - that is, a string of the form rgb(r,g,b) where each of r, g, and b
3813    * are integers in the range [0,255].
3814    */
3815   getCSSIntegerRGB : function(){
3816
3817     // get the integer RGB components
3818     var rgb = this.getIntegerRGB();
3819
3820     // return the CSS RGB Color value
3821     return 'rgb(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ')';
3822
3823   },
3824
3825   /**
3826    * getCSSIntegerRGBA
3827    * @return {String} Returns a string representing this Color as a CSS integer RGBA Color
3828    * value - that is, a string of the form rgba(r,g,b,a) where each of r, g, and
3829    * b are integers in the range [0,255] and a is in the range [0,1].
3830    */
3831   getCSSIntegerRGBA : function(){
3832
3833     // get the integer RGB components
3834     var rgb = this.getIntegerRGB();
3835
3836     // return the CSS integer RGBA Color value
3837     return 'rgb(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ',' + rgb.a + ')';
3838
3839   },
3840
3841   /**
3842    * getCSSPercentageRGB
3843    * @return {String} a string representing this Color as a CSS percentage RGB Color
3844    * value - that is, a string of the form rgb(r%,g%,b%) where each of r, g, and
3845    * b are in the range [0,100].
3846    */
3847   getCSSPercentageRGB : function(){
3848
3849     // get the percentage RGB components
3850     var rgb = this.getPercentageRGB();
3851
3852     // return the CSS RGB Color value
3853     return 'rgb(' + rgb.r + '%,' + rgb.g + '%,' + rgb.b + '%)';
3854
3855   },
3856
3857   /**
3858    * getCSSPercentageRGBA
3859    * @return {String} a string representing this Color as a CSS percentage RGBA Color
3860    * value - that is, a string of the form rgba(r%,g%,b%,a) where each of r, g,
3861    * and b are in the range [0,100] and a is in the range [0,1].
3862    */
3863   getCSSPercentageRGBA : function(){
3864
3865     // get the percentage RGB components
3866     var rgb = this.getPercentageRGB();
3867
3868     // return the CSS percentage RGBA Color value
3869     return 'rgb(' + rgb.r + '%,' + rgb.g + '%,' + rgb.b + '%,' + rgb.a + ')';
3870
3871   },
3872
3873   /**
3874    * getCSSHSL
3875    * @return {String} a string representing this Color as a CSS HSL Color value - that
3876    * is, a string of the form hsl(h,s%,l%) where h is in the range [0,100] and
3877    * s and l are in the range [0,100].
3878    */
3879   getCSSHSL : function(){
3880
3881     // get the HSL components
3882     var hsl = this.getHSL();
3883
3884     // return the CSS HSL Color value
3885     return 'hsl(' + hsl.h + ',' + hsl.s + '%,' + hsl.l + '%)';
3886
3887   },
3888
3889   /**
3890    * getCSSHSLA
3891    * @return {String} a string representing this Color as a CSS HSLA Color value - that
3892    * is, a string of the form hsla(h,s%,l%,a) where h is in the range [0,100],
3893    * s and l are in the range [0,100], and a is in the range [0,1].
3894    */
3895   getCSSHSLA : function(){
3896
3897     // get the HSL components
3898     var hsl = this.getHSL();
3899
3900     // return the CSS HSL Color value
3901     return 'hsl(' + hsl.h + ',' + hsl.s + '%,' + hsl.l + '%,' + hsl.a + ')';
3902
3903   },
3904
3905   /**
3906    * Sets the Color of the specified node to this Color. This functions sets
3907    * the CSS 'color' property for the node. The parameter is:
3908    * 
3909    * @param {DomElement} node - the node whose Color should be set
3910    */
3911   setNodeColor : function(node){
3912
3913     // set the Color of the node
3914     node.style.color = this.getCSSHexadecimalRGB();
3915
3916   },
3917
3918   /**
3919    * Sets the background Color of the specified node to this Color. This
3920    * functions sets the CSS 'background-color' property for the node. The
3921    * parameter is:
3922    *
3923    * @param {DomElement} node - the node whose background Color should be set
3924    */
3925   setNodeBackgroundColor : function(node){
3926
3927     // set the background Color of the node
3928     node.style.backgroundColor = this.getCSSHexadecimalRGB();
3929
3930   },
3931   // convert between formats..
3932   toRGB: function()
3933   {
3934     var r = this.getIntegerRGB();
3935     return new Roo.lib.RGBColor(r.r,r.g,r.b,r.a);
3936     
3937   },
3938   toHSL : function()
3939   {
3940      var hsl = this.getHSL();
3941   // return the CSS HSL Color value
3942     return new Roo.lib.HSLColor(hsl.h,  hsl.s, hsl.l ,  hsl.a );
3943     
3944   },
3945   
3946   toHSV : function()
3947   {
3948     var rgb = this.toRGB();
3949     var hsv = rgb.getHSV();
3950    // return the CSS HSL Color value
3951     return new Roo.lib.HSVColor(hsv.h,  hsv.s, hsv.v ,  hsv.a );
3952     
3953   },
3954   
3955   // modify  v = 0 ... 1 (eg. 0.5)
3956   saturate : function(v)
3957   {
3958       var rgb = this.toRGB();
3959       var hsv = rgb.getHSV();
3960       return new Roo.lib.HSVColor(hsv.h,  hsv.s * v, hsv.v ,  hsv.a );
3961       
3962   
3963   },
3964   
3965    
3966   /**
3967    * getRGB
3968    * @return {Object} the RGB and alpha components of this Color as an object with r,
3969    * g, b, and a properties. r, g, and b are in the range [0,255] and a is in
3970    * the range [0,1].
3971    */
3972   getRGB: function(){
3973    
3974     // return the RGB components
3975     return {
3976       'r' : this.rgb.r,
3977       'g' : this.rgb.g,
3978       'b' : this.rgb.b,
3979       'a' : this.alpha
3980     };
3981
3982   },
3983
3984   /**
3985    * getHSV
3986    * @return {Object} the HSV and alpha components of this Color as an object with h,
3987    * s, v, and a properties. h is in the range [0,360), s and v are in the range
3988    * [0,100], and a is in the range [0,1].
3989    */
3990   getHSV : function()
3991   {
3992     
3993     // calculate the HSV components if necessary
3994     if (this.hsv == null) {
3995       this.calculateHSV();
3996     }
3997
3998     // return the HSV components
3999     return {
4000       'h' : this.hsv.h,
4001       's' : this.hsv.s,
4002       'v' : this.hsv.v,
4003       'a' : this.alpha
4004     };
4005
4006   },
4007
4008   /**
4009    * getHSL
4010    * @return {Object} the HSL and alpha components of this Color as an object with h,
4011    * s, l, and a properties. h is in the range [0,360), s and l are in the range
4012    * [0,100], and a is in the range [0,1].
4013    */
4014   getHSL : function(){
4015     
4016      
4017     // calculate the HSV components if necessary
4018     if (this.hsl == null) { this.calculateHSL(); }
4019
4020     // return the HSL components
4021     return {
4022       'h' : this.hsl.h,
4023       's' : this.hsl.s,
4024       'l' : this.hsl.l,
4025       'a' : this.alpha
4026     };
4027
4028   }
4029   
4030
4031 });
4032
4033
4034 /**
4035  * @class Roo.lib.RGBColor
4036  * @extends Roo.lib.Color
4037  * Creates a Color specified in the RGB Color space, with an optional alpha
4038  * component. The parameters are:
4039  * @constructor
4040  * 
4041
4042  * @param {Number} r - the red component, clipped to the range [0,255]
4043  * @param {Number} g - the green component, clipped to the range [0,255]
4044  * @param {Number} b - the blue component, clipped to the range [0,255]
4045  * @param {Number} a - the alpha component, clipped to the range [0,1] - this parameter is
4046  *     optional and defaults to 1
4047  */
4048 Roo.lib.RGBColor = function (r, g, b, a){
4049
4050   // store the alpha component after clipping it if necessary
4051   this.alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
4052
4053   // store the RGB components after clipping them if necessary
4054   this.rgb =
4055       {
4056         'r' : Math.max(0, Math.min(255, r)),
4057         'g' : Math.max(0, Math.min(255, g)),
4058         'b' : Math.max(0, Math.min(255, b))
4059       };
4060
4061   // initialise the HSV and HSL components to null
4062   
4063
4064   /* 
4065    * //private returns the HSV or HSL hue component of this RGBColor. The hue is in the
4066    * range [0,360). The parameters are:
4067    *
4068    * maximum - the maximum of the RGB component values
4069    * range   - the range of the RGB component values
4070    */
4071    
4072
4073 }
4074 // this does an 'exteds'
4075 Roo.extend(Roo.lib.RGBColor, Roo.lib.Color, {
4076
4077   
4078     getHue  : function(maximum, range)
4079     {
4080       var rgb = this.rgb;
4081        
4082       // check whether the range is zero
4083       if (range == 0){
4084   
4085         // set the hue to zero (any hue is acceptable as the Color is grey)
4086         var hue = 0;
4087   
4088       }else{
4089   
4090         // determine which of the components has the highest value and set the hue
4091         switch (maximum){
4092   
4093           // red has the highest value
4094           case rgb.r:
4095             var hue = (rgb.g - rgb.b) / range * 60;
4096             if (hue < 0) { hue += 360; }
4097             break;
4098   
4099           // green has the highest value
4100           case rgb.g:
4101             var hue = (rgb.b - rgb.r) / range * 60 + 120;
4102             break;
4103   
4104           // blue has the highest value
4105           case rgb.b:
4106             var hue = (rgb.r - rgb.g) / range * 60 + 240;
4107             break;
4108   
4109         }
4110   
4111       }
4112   
4113       // return the hue
4114       return hue;
4115   
4116     },
4117
4118   /* //private Calculates and stores the HSV components of this RGBColor so that they can
4119    * be returned be the getHSV function.
4120    */
4121    calculateHSV : function(){
4122     var rgb = this.rgb;
4123     // get the maximum and range of the RGB component values
4124     var maximum = Math.max(rgb.r, rgb.g, rgb.b);
4125     var range   = maximum - Math.min(rgb.r, rgb.g, rgb.b);
4126
4127     // store the HSV components
4128     this.hsv =
4129         {
4130           'h' : this.getHue(maximum, range),
4131           's' : (maximum == 0 ? 0 : 100 * range / maximum),
4132           'v' : maximum / 2.55
4133         };
4134
4135   },
4136
4137   /* //private Calculates and stores the HSL components of this RGBColor so that they can
4138    * be returned be the getHSL function.
4139    */
4140    calculateHSL : function(){
4141     var rgb = this.rgb;
4142     // get the maximum and range of the RGB component values
4143     var maximum = Math.max(rgb.r, rgb.g, rgb.b);
4144     var range   = maximum - Math.min(rgb.r, rgb.g, rgb.b);
4145
4146     // determine the lightness in the range [0,1]
4147     var l = maximum / 255 - range / 510;
4148
4149     // store the HSL components
4150     this.hsl =
4151         {
4152           'h' : this.getHue(maximum, range),
4153           's' : (range == 0 ? 0 : range / 2.55 / (l < 0.5 ? l * 2 : 2 - l * 2)),
4154           'l' : 100 * l
4155         };
4156
4157   }
4158
4159 });
4160
4161 /**
4162  * @class Roo.lib.HSVColor
4163  * @extends Roo.lib.Color
4164  * Creates a Color specified in the HSV Color space, with an optional alpha
4165  * component. The parameters are:
4166  * @constructor
4167  *
4168  * @param {Number} h - the hue component, wrapped to the range [0,360)
4169  * @param {Number} s - the saturation component, clipped to the range [0,100]
4170  * @param {Number} v - the value component, clipped to the range [0,100]
4171  * @param {Number} a - the alpha component, clipped to the range [0,1] - this parameter is
4172  *     optional and defaults to 1
4173  */
4174 Roo.lib.HSVColor = function (h, s, v, a){
4175
4176   // store the alpha component after clipping it if necessary
4177   this.alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
4178
4179   // store the HSV components after clipping or wrapping them if necessary
4180   this.hsv =
4181       {
4182         'h' : (h % 360 + 360) % 360,
4183         's' : Math.max(0, Math.min(100, s)),
4184         'v' : Math.max(0, Math.min(100, v))
4185       };
4186
4187   // initialise the RGB and HSL components to null
4188   this.rgb = null;
4189   this.hsl = null;
4190 }
4191
4192 Roo.extend(Roo.lib.HSVColor, Roo.lib.Color, {
4193   /* Calculates and stores the RGB components of this HSVColor so that they can
4194    * be returned be the getRGB function.
4195    */
4196   calculateRGB: function ()
4197   {
4198     var hsv = this.hsv;
4199     // check whether the saturation is zero
4200     if (hsv.s == 0){
4201
4202       // set the Color to the appropriate shade of grey
4203       var r = hsv.v;
4204       var g = hsv.v;
4205       var b = hsv.v;
4206
4207     }else{
4208
4209       // set some temporary values
4210       var f  = hsv.h / 60 - Math.floor(hsv.h / 60);
4211       var p  = hsv.v * (1 - hsv.s / 100);
4212       var q  = hsv.v * (1 - hsv.s / 100 * f);
4213       var t  = hsv.v * (1 - hsv.s / 100 * (1 - f));
4214
4215       // set the RGB Color components to their temporary values
4216       switch (Math.floor(hsv.h / 60)){
4217         case 0: var r = hsv.v; var g = t; var b = p; break;
4218         case 1: var r = q; var g = hsv.v; var b = p; break;
4219         case 2: var r = p; var g = hsv.v; var b = t; break;
4220         case 3: var r = p; var g = q; var b = hsv.v; break;
4221         case 4: var r = t; var g = p; var b = hsv.v; break;
4222         case 5: var r = hsv.v; var g = p; var b = q; break;
4223       }
4224
4225     }
4226
4227     // store the RGB components
4228     this.rgb =
4229         {
4230           'r' : r * 2.55,
4231           'g' : g * 2.55,
4232           'b' : b * 2.55
4233         };
4234
4235   },
4236
4237   /* Calculates and stores the HSL components of this HSVColor so that they can
4238    * be returned be the getHSL function.
4239    */
4240   calculateHSL : function (){
4241
4242     var hsv = this.hsv;
4243     // determine the lightness in the range [0,100]
4244     var l = (2 - hsv.s / 100) * hsv.v / 2;
4245
4246     // store the HSL components
4247     this.hsl =
4248         {
4249           'h' : hsv.h,
4250           's' : hsv.s * hsv.v / (l < 50 ? l * 2 : 200 - l * 2),
4251           'l' : l
4252         };
4253
4254     // correct a division-by-zero error
4255     if (isNaN(hsl.s)) { hsl.s = 0; }
4256
4257   } 
4258  
4259
4260 });
4261  
4262
4263 /**
4264  * @class Roo.lib.HSLColor
4265  * @extends Roo.lib.Color
4266  *
4267  * @constructor
4268  * Creates a Color specified in the HSL Color space, with an optional alpha
4269  * component. The parameters are:
4270  *
4271  * @param {Number} h - the hue component, wrapped to the range [0,360)
4272  * @param {Number} s - the saturation component, clipped to the range [0,100]
4273  * @param {Number} l - the lightness component, clipped to the range [0,100]
4274  * @param {Number} a - the alpha component, clipped to the range [0,1] - this parameter is
4275  *     optional and defaults to 1
4276  */
4277
4278 Roo.lib.HSLColor = function(h, s, l, a){
4279
4280   // store the alpha component after clipping it if necessary
4281   this.alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
4282
4283   // store the HSL components after clipping or wrapping them if necessary
4284   this.hsl =
4285       {
4286         'h' : (h % 360 + 360) % 360,
4287         's' : Math.max(0, Math.min(100, s)),
4288         'l' : Math.max(0, Math.min(100, l))
4289       };
4290
4291   // initialise the RGB and HSV components to null
4292 }
4293
4294 Roo.extend(Roo.lib.HSLColor, Roo.lib.Color, {
4295
4296   /* Calculates and stores the RGB components of this HSLColor so that they can
4297    * be returned be the getRGB function.
4298    */
4299   calculateRGB: function (){
4300
4301     // check whether the saturation is zero
4302     if (this.hsl.s == 0){
4303
4304       // store the RGB components representing the appropriate shade of grey
4305       this.rgb =
4306           {
4307             'r' : this.hsl.l * 2.55,
4308             'g' : this.hsl.l * 2.55,
4309             'b' : this.hsl.l * 2.55
4310           };
4311
4312     }else{
4313
4314       // set some temporary values
4315       var p = this.hsl.l < 50
4316             ? this.hsl.l * (1 + hsl.s / 100)
4317             : this.hsl.l + hsl.s - hsl.l * hsl.s / 100;
4318       var q = 2 * hsl.l - p;
4319
4320       // initialise the RGB components
4321       this.rgb =
4322           {
4323             'r' : (h + 120) / 60 % 6,
4324             'g' : h / 60,
4325             'b' : (h + 240) / 60 % 6
4326           };
4327
4328       // loop over the RGB components
4329       for (var key in this.rgb){
4330
4331         // ensure that the property is not inherited from the root object
4332         if (this.rgb.hasOwnProperty(key)){
4333
4334           // set the component to its value in the range [0,100]
4335           if (this.rgb[key] < 1){
4336             this.rgb[key] = q + (p - q) * this.rgb[key];
4337           }else if (this.rgb[key] < 3){
4338             this.rgb[key] = p;
4339           }else if (this.rgb[key] < 4){
4340             this.rgb[key] = q + (p - q) * (4 - this.rgb[key]);
4341           }else{
4342             this.rgb[key] = q;
4343           }
4344
4345           // set the component to its value in the range [0,255]
4346           this.rgb[key] *= 2.55;
4347
4348         }
4349
4350       }
4351
4352     }
4353
4354   },
4355
4356   /* Calculates and stores the HSV components of this HSLColor so that they can
4357    * be returned be the getHSL function.
4358    */
4359    calculateHSV : function(){
4360
4361     // set a temporary value
4362     var t = this.hsl.s * (this.hsl.l < 50 ? this.hsl.l : 100 - this.hsl.l) / 100;
4363
4364     // store the HSV components
4365     this.hsv =
4366         {
4367           'h' : this.hsl.h,
4368           's' : 200 * t / (this.hsl.l + t),
4369           'v' : t + this.hsl.l
4370         };
4371
4372     // correct a division-by-zero error
4373     if (isNaN(this.hsv.s)) { this.hsv.s = 0; }
4374
4375   }
4376  
4377
4378 });
4379 /*
4380  * Portions of this file are based on pieces of Yahoo User Interface Library
4381  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4382  * YUI licensed under the BSD License:
4383  * http://developer.yahoo.net/yui/license.txt
4384  * <script type="text/javascript">
4385  *
4386  */
4387 (function() {
4388
4389     Roo.lib.ColorAnim = function(el, attributes, duration, method) {
4390         Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
4391     };
4392
4393     Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
4394
4395     var fly = Roo.lib.AnimBase.fly;
4396     var Y = Roo.lib;
4397     var superclass = Y.ColorAnim.superclass;
4398     var proto = Y.ColorAnim.prototype;
4399
4400     proto.toString = function() {
4401         var el = this.getEl();
4402         var id = el.id || el.tagName;
4403         return ("ColorAnim " + id);
4404     };
4405
4406     proto.patterns.color = /color$/i;
4407     proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
4408     proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
4409     proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
4410     proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
4411
4412
4413     proto.parseColor = function(s) {
4414         if (s.length == 3) {
4415             return s;
4416         }
4417
4418         var c = this.patterns.hex.exec(s);
4419         if (c && c.length == 4) {
4420             return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
4421         }
4422
4423         c = this.patterns.rgb.exec(s);
4424         if (c && c.length == 4) {
4425             return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
4426         }
4427
4428         c = this.patterns.hex3.exec(s);
4429         if (c && c.length == 4) {
4430             return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
4431         }
4432
4433         return null;
4434     };
4435     // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
4436     proto.getAttribute = function(attr) {
4437         var el = this.getEl();
4438         if (this.patterns.color.test(attr)) {
4439             var val = fly(el).getStyle(attr);
4440
4441             if (this.patterns.transparent.test(val)) {
4442                 var parent = el.parentNode;
4443                 val = fly(parent).getStyle(attr);
4444
4445                 while (parent && this.patterns.transparent.test(val)) {
4446                     parent = parent.parentNode;
4447                     val = fly(parent).getStyle(attr);
4448                     if (parent.tagName.toUpperCase() == 'HTML') {
4449                         val = '#fff';
4450                     }
4451                 }
4452             }
4453         } else {
4454             val = superclass.getAttribute.call(this, attr);
4455         }
4456
4457         return val;
4458     };
4459     proto.getAttribute = function(attr) {
4460         var el = this.getEl();
4461         if (this.patterns.color.test(attr)) {
4462             var val = fly(el).getStyle(attr);
4463
4464             if (this.patterns.transparent.test(val)) {
4465                 var parent = el.parentNode;
4466                 val = fly(parent).getStyle(attr);
4467
4468                 while (parent && this.patterns.transparent.test(val)) {
4469                     parent = parent.parentNode;
4470                     val = fly(parent).getStyle(attr);
4471                     if (parent.tagName.toUpperCase() == 'HTML') {
4472                         val = '#fff';
4473                     }
4474                 }
4475             }
4476         } else {
4477             val = superclass.getAttribute.call(this, attr);
4478         }
4479
4480         return val;
4481     };
4482
4483     proto.doMethod = function(attr, start, end) {
4484         var val;
4485
4486         if (this.patterns.color.test(attr)) {
4487             val = [];
4488             for (var i = 0, len = start.length; i < len; ++i) {
4489                 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
4490             }
4491
4492             val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
4493         }
4494         else {
4495             val = superclass.doMethod.call(this, attr, start, end);
4496         }
4497
4498         return val;
4499     };
4500
4501     proto.setRuntimeAttribute = function(attr) {
4502         superclass.setRuntimeAttribute.call(this, attr);
4503
4504         if (this.patterns.color.test(attr)) {
4505             var attributes = this.attributes;
4506             var start = this.parseColor(this.runtimeAttributes[attr].start);
4507             var end = this.parseColor(this.runtimeAttributes[attr].end);
4508
4509             if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
4510                 end = this.parseColor(attributes[attr].by);
4511
4512                 for (var i = 0, len = start.length; i < len; ++i) {
4513                     end[i] = start[i] + end[i];
4514                 }
4515             }
4516
4517             this.runtimeAttributes[attr].start = start;
4518             this.runtimeAttributes[attr].end = end;
4519         }
4520     };
4521 })();
4522
4523 /*
4524  * Portions of this file are based on pieces of Yahoo User Interface Library
4525  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4526  * YUI licensed under the BSD License:
4527  * http://developer.yahoo.net/yui/license.txt
4528  * <script type="text/javascript">
4529  *
4530  */
4531 Roo.lib.Easing = {
4532
4533
4534     easeNone: function (t, b, c, d) {
4535         return c * t / d + b;
4536     },
4537
4538
4539     easeIn: function (t, b, c, d) {
4540         return c * (t /= d) * t + b;
4541     },
4542
4543
4544     easeOut: function (t, b, c, d) {
4545         return -c * (t /= d) * (t - 2) + b;
4546     },
4547
4548
4549     easeBoth: function (t, b, c, d) {
4550         if ((t /= d / 2) < 1) {
4551             return c / 2 * t * t + b;
4552         }
4553
4554         return -c / 2 * ((--t) * (t - 2) - 1) + b;
4555     },
4556
4557
4558     easeInStrong: function (t, b, c, d) {
4559         return c * (t /= d) * t * t * t + b;
4560     },
4561
4562
4563     easeOutStrong: function (t, b, c, d) {
4564         return -c * ((t = t / d - 1) * t * t * t - 1) + b;
4565     },
4566
4567
4568     easeBothStrong: function (t, b, c, d) {
4569         if ((t /= d / 2) < 1) {
4570             return c / 2 * t * t * t * t + b;
4571         }
4572
4573         return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
4574     },
4575
4576
4577
4578     elasticIn: function (t, b, c, d, a, p) {
4579         if (t == 0) {
4580             return b;
4581         }
4582         if ((t /= d) == 1) {
4583             return b + c;
4584         }
4585         if (!p) {
4586             p = d * .3;
4587         }
4588
4589         if (!a || a < Math.abs(c)) {
4590             a = c;
4591             var s = p / 4;
4592         }
4593         else {
4594             var s = p / (2 * Math.PI) * Math.asin(c / a);
4595         }
4596
4597         return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
4598     },
4599
4600
4601     elasticOut: function (t, b, c, d, a, p) {
4602         if (t == 0) {
4603             return b;
4604         }
4605         if ((t /= d) == 1) {
4606             return b + c;
4607         }
4608         if (!p) {
4609             p = d * .3;
4610         }
4611
4612         if (!a || a < Math.abs(c)) {
4613             a = c;
4614             var s = p / 4;
4615         }
4616         else {
4617             var s = p / (2 * Math.PI) * Math.asin(c / a);
4618         }
4619
4620         return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
4621     },
4622
4623
4624     elasticBoth: function (t, b, c, d, a, p) {
4625         if (t == 0) {
4626             return b;
4627         }
4628
4629         if ((t /= d / 2) == 2) {
4630             return b + c;
4631         }
4632
4633         if (!p) {
4634             p = d * (.3 * 1.5);
4635         }
4636
4637         if (!a || a < Math.abs(c)) {
4638             a = c;
4639             var s = p / 4;
4640         }
4641         else {
4642             var s = p / (2 * Math.PI) * Math.asin(c / a);
4643         }
4644
4645         if (t < 1) {
4646             return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
4647                           Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
4648         }
4649         return a * Math.pow(2, -10 * (t -= 1)) *
4650                Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
4651     },
4652
4653
4654
4655     backIn: function (t, b, c, d, s) {
4656         if (typeof s == 'undefined') {
4657             s = 1.70158;
4658         }
4659         return c * (t /= d) * t * ((s + 1) * t - s) + b;
4660     },
4661
4662
4663     backOut: function (t, b, c, d, s) {
4664         if (typeof s == 'undefined') {
4665             s = 1.70158;
4666         }
4667         return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
4668     },
4669
4670
4671     backBoth: function (t, b, c, d, s) {
4672         if (typeof s == 'undefined') {
4673             s = 1.70158;
4674         }
4675
4676         if ((t /= d / 2 ) < 1) {
4677             return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
4678         }
4679         return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
4680     },
4681
4682
4683     bounceIn: function (t, b, c, d) {
4684         return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
4685     },
4686
4687
4688     bounceOut: function (t, b, c, d) {
4689         if ((t /= d) < (1 / 2.75)) {
4690             return c * (7.5625 * t * t) + b;
4691         } else if (t < (2 / 2.75)) {
4692             return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
4693         } else if (t < (2.5 / 2.75)) {
4694             return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
4695         }
4696         return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
4697     },
4698
4699
4700     bounceBoth: function (t, b, c, d) {
4701         if (t < d / 2) {
4702             return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
4703         }
4704         return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
4705     }
4706 };/*
4707  * Portions of this file are based on pieces of Yahoo User Interface Library
4708  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4709  * YUI licensed under the BSD License:
4710  * http://developer.yahoo.net/yui/license.txt
4711  * <script type="text/javascript">
4712  *
4713  */
4714     (function() {
4715         Roo.lib.Motion = function(el, attributes, duration, method) {
4716             if (el) {
4717                 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
4718             }
4719         };
4720
4721         Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
4722
4723
4724         var Y = Roo.lib;
4725         var superclass = Y.Motion.superclass;
4726         var proto = Y.Motion.prototype;
4727
4728         proto.toString = function() {
4729             var el = this.getEl();
4730             var id = el.id || el.tagName;
4731             return ("Motion " + id);
4732         };
4733
4734         proto.patterns.points = /^points$/i;
4735
4736         proto.setAttribute = function(attr, val, unit) {
4737             if (this.patterns.points.test(attr)) {
4738                 unit = unit || 'px';
4739                 superclass.setAttribute.call(this, 'left', val[0], unit);
4740                 superclass.setAttribute.call(this, 'top', val[1], unit);
4741             } else {
4742                 superclass.setAttribute.call(this, attr, val, unit);
4743             }
4744         };
4745
4746         proto.getAttribute = function(attr) {
4747             if (this.patterns.points.test(attr)) {
4748                 var val = [
4749                         superclass.getAttribute.call(this, 'left'),
4750                         superclass.getAttribute.call(this, 'top')
4751                         ];
4752             } else {
4753                 val = superclass.getAttribute.call(this, attr);
4754             }
4755
4756             return val;
4757         };
4758
4759         proto.doMethod = function(attr, start, end) {
4760             var val = null;
4761
4762             if (this.patterns.points.test(attr)) {
4763                 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
4764                 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
4765             } else {
4766                 val = superclass.doMethod.call(this, attr, start, end);
4767             }
4768             return val;
4769         };
4770
4771         proto.setRuntimeAttribute = function(attr) {
4772             if (this.patterns.points.test(attr)) {
4773                 var el = this.getEl();
4774                 var attributes = this.attributes;
4775                 var start;
4776                 var control = attributes['points']['control'] || [];
4777                 var end;
4778                 var i, len;
4779
4780                 if (control.length > 0 && !(control[0] instanceof Array)) {
4781                     control = [control];
4782                 } else {
4783                     var tmp = [];
4784                     for (i = 0,len = control.length; i < len; ++i) {
4785                         tmp[i] = control[i];
4786                     }
4787                     control = tmp;
4788                 }
4789
4790                 Roo.fly(el).position();
4791
4792                 if (isset(attributes['points']['from'])) {
4793                     Roo.lib.Dom.setXY(el, attributes['points']['from']);
4794                 }
4795                 else {
4796                     Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
4797                 }
4798
4799                 start = this.getAttribute('points');
4800
4801
4802                 if (isset(attributes['points']['to'])) {
4803                     end = translateValues.call(this, attributes['points']['to'], start);
4804
4805                     var pageXY = Roo.lib.Dom.getXY(this.getEl());
4806                     for (i = 0,len = control.length; i < len; ++i) {
4807                         control[i] = translateValues.call(this, control[i], start);
4808                     }
4809
4810
4811                 } else if (isset(attributes['points']['by'])) {
4812                     end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4813
4814                     for (i = 0,len = control.length; i < len; ++i) {
4815                         control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4816                     }
4817                 }
4818
4819                 this.runtimeAttributes[attr] = [start];
4820
4821                 if (control.length > 0) {
4822                     this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4823                 }
4824
4825                 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4826             }
4827             else {
4828                 superclass.setRuntimeAttribute.call(this, attr);
4829             }
4830         };
4831
4832         var translateValues = function(val, start) {
4833             var pageXY = Roo.lib.Dom.getXY(this.getEl());
4834             val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4835
4836             return val;
4837         };
4838
4839         var isset = function(prop) {
4840             return (typeof prop !== 'undefined');
4841         };
4842     })();
4843 /*
4844  * Portions of this file are based on pieces of Yahoo User Interface Library
4845  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4846  * YUI licensed under the BSD License:
4847  * http://developer.yahoo.net/yui/license.txt
4848  * <script type="text/javascript">
4849  *
4850  */
4851     (function() {
4852         Roo.lib.Scroll = function(el, attributes, duration, method) {
4853             if (el) {
4854                 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4855             }
4856         };
4857
4858         Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4859
4860
4861         var Y = Roo.lib;
4862         var superclass = Y.Scroll.superclass;
4863         var proto = Y.Scroll.prototype;
4864
4865         proto.toString = function() {
4866             var el = this.getEl();
4867             var id = el.id || el.tagName;
4868             return ("Scroll " + id);
4869         };
4870
4871         proto.doMethod = function(attr, start, end) {
4872             var val = null;
4873
4874             if (attr == 'scroll') {
4875                 val = [
4876                         this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4877                         this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4878                         ];
4879
4880             } else {
4881                 val = superclass.doMethod.call(this, attr, start, end);
4882             }
4883             return val;
4884         };
4885
4886         proto.getAttribute = function(attr) {
4887             var val = null;
4888             var el = this.getEl();
4889
4890             if (attr == 'scroll') {
4891                 val = [ el.scrollLeft, el.scrollTop ];
4892             } else {
4893                 val = superclass.getAttribute.call(this, attr);
4894             }
4895
4896             return val;
4897         };
4898
4899         proto.setAttribute = function(attr, val, unit) {
4900             var el = this.getEl();
4901
4902             if (attr == 'scroll') {
4903                 el.scrollLeft = val[0];
4904                 el.scrollTop = val[1];
4905             } else {
4906                 superclass.setAttribute.call(this, attr, val, unit);
4907             }
4908         };
4909     })();
4910 /**
4911  * Originally based of this code... - refactored for Roo...
4912  * https://github.com/aaalsaleh/undo-manager
4913  
4914  * undo-manager.js
4915  * @author  Abdulrahman Alsaleh 
4916  * @copyright 2015 Abdulrahman Alsaleh 
4917  * @license  MIT License (c) 
4918  *
4919  * Hackily modifyed by alan@roojs.com
4920  *
4921  *
4922  *  
4923  *
4924  *  TOTALLY UNTESTED...
4925  *
4926  *  Documentation to be done....
4927  */
4928  
4929
4930 /**
4931 * @class Roo.lib.UndoManager
4932 * An undo manager implementation in JavaScript. It follows the W3C UndoManager and DOM Transaction
4933 * Draft and the undocumented and disabled Mozilla Firefox's UndoManager implementation.
4934
4935  * Usage:
4936  * <pre><code>
4937
4938
4939 editor.undoManager = new Roo.lib.UndoManager(1000, editor);
4940  
4941 </code></pre>
4942
4943 * For more information see this blog post with examples:
4944 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4945      - Create Elements using DOM, HTML fragments and Templates</a>. 
4946 * @constructor
4947 * @param {Number} limit how far back to go ... use 1000?
4948 * @param {Object} scope usually use document..
4949 */
4950
4951 Roo.lib.UndoManager = function (limit, undoScopeHost)
4952 {
4953     this.stack = [];
4954     this.limit = limit;
4955     this.scope = undoScopeHost;
4956     this.fireEvent = typeof CustomEvent != 'undefined' && undoScopeHost && undoScopeHost.dispatchEvent;
4957     if (this.fireEvent) {
4958         this.bindEvents();
4959     }
4960     this.reset();
4961     
4962 };
4963         
4964 Roo.lib.UndoManager.prototype = {
4965     
4966     limit : false,
4967     stack : false,
4968     scope :  false,
4969     fireEvent : false,
4970     position : 0,
4971     length : 0,
4972     
4973     
4974      /**
4975      * To push and execute a transaction, the method undoManager.transact
4976      * must be called by passing a transaction object as the first argument, and a merge
4977      * flag as the second argument. A transaction object has the following properties:
4978      *
4979      * Usage:
4980 <pre><code>
4981 undoManager.transact({
4982     label: 'Typing',
4983     execute: function() { ... },
4984     undo: function() { ... },
4985     // redo same as execute
4986     redo: function() { this.execute(); }
4987 }, false);
4988
4989 // merge transaction
4990 undoManager.transact({
4991     label: 'Typing',
4992     execute: function() { ... },  // this will be run...
4993     undo: function() { ... }, // what to do when undo is run.
4994     // redo same as execute
4995     redo: function() { this.execute(); }
4996 }, true); 
4997 </code></pre> 
4998      *
4999      * 
5000      * @param {Object} transaction The transaction to add to the stack.
5001      * @return {String} The HTML fragment
5002      */
5003     
5004     
5005     transact : function (transaction, merge)
5006     {
5007         if (arguments.length < 2) {
5008             throw new TypeError('Not enough arguments to UndoManager.transact.');
5009         }
5010
5011         transaction.execute();
5012
5013         this.stack.splice(0, this.position);
5014         if (merge && this.length) {
5015             this.stack[0].push(transaction);
5016         } else {
5017             this.stack.unshift([transaction]);
5018         }
5019     
5020         this.position = 0;
5021
5022         if (this.limit && this.stack.length > this.limit) {
5023             this.length = this.stack.length = this.limit;
5024         } else {
5025             this.length = this.stack.length;
5026         }
5027
5028         if (this.fireEvent) {
5029             this.scope.dispatchEvent(
5030                 new CustomEvent('DOMTransaction', {
5031                     detail: {
5032                         transactions: this.stack[0].slice()
5033                     },
5034                     bubbles: true,
5035                     cancelable: false
5036                 })
5037             );
5038         }
5039         
5040         //Roo.log("transaction: pos:" + this.position + " len: " + this.length + " slen:" + this.stack.length);
5041       
5042         
5043     },
5044
5045     undo : function ()
5046     {
5047         //Roo.log("undo: pos:" + this.position + " len: " + this.length + " slen:" + this.stack.length);
5048         
5049         if (this.position < this.length) {
5050             for (var i = this.stack[this.position].length - 1; i >= 0; i--) {
5051                 this.stack[this.position][i].undo();
5052             }
5053             this.position++;
5054
5055             if (this.fireEvent) {
5056                 this.scope.dispatchEvent(
5057                     new CustomEvent('undo', {
5058                         detail: {
5059                             transactions: this.stack[this.position - 1].slice()
5060                         },
5061                         bubbles: true,
5062                         cancelable: false
5063                     })
5064                 );
5065             }
5066         }
5067     },
5068
5069     redo : function ()
5070     {
5071         if (this.position > 0) {
5072             for (var i = 0, n = this.stack[this.position - 1].length; i < n; i++) {
5073                 this.stack[this.position - 1][i].redo();
5074             }
5075             this.position--;
5076
5077             if (this.fireEvent) {
5078                 this.scope.dispatchEvent(
5079                     new CustomEvent('redo', {
5080                         detail: {
5081                             transactions: this.stack[this.position].slice()
5082                         },
5083                         bubbles: true,
5084                         cancelable: false
5085                     })
5086                 );
5087             }
5088         }
5089     },
5090
5091     item : function (index)
5092     {
5093         if (index >= 0 && index < this.length) {
5094             return this.stack[index].slice();
5095         }
5096         return null;
5097     },
5098
5099     clearUndo : function () {
5100         this.stack.length = this.length = this.position;
5101     },
5102
5103     clearRedo : function () {
5104         this.stack.splice(0, this.position);
5105         this.position = 0;
5106         this.length = this.stack.length;
5107     },
5108     /**
5109      * Reset the undo - probaly done on load to clear all history.
5110      */
5111     reset : function()
5112     {
5113         this.stack = [];
5114         this.position = 0;
5115         this.length = 0;
5116         this.current_html = this.scope.innerHTML;
5117         if (this.timer !== false) {
5118             clearTimeout(this.timer);
5119         }
5120         this.timer = false;
5121         this.merge = false;
5122         this.addEvent();
5123         
5124     },
5125     current_html : '',
5126     timer : false,
5127     merge : false,
5128     
5129     
5130     // this will handle the undo/redo on the element.?
5131     bindEvents : function()
5132     {
5133         var el  = this.scope;
5134         el.undoManager = this;
5135         
5136         
5137         this.scope.addEventListener('keydown', function(e) {
5138             if ((e.ctrlKey || e.metaKey) && e.keyCode === 90) {
5139                 if (e.shiftKey) {
5140                     el.undoManager.redo(); // Ctrl/Command + Shift + Z
5141                 } else {
5142                     el.undoManager.undo(); // Ctrl/Command + Z
5143                 }
5144         
5145                 e.preventDefault();
5146             }
5147         });
5148         /// ignore keyup..
5149         this.scope.addEventListener('keyup', function(e) {
5150             if ((e.ctrlKey || e.metaKey) && e.keyCode === 90) {
5151                 e.preventDefault();
5152             }
5153         });
5154         
5155         
5156         
5157         var t = this;
5158         
5159         el.addEventListener('input', function(e) {
5160             if(el.innerHTML == t.current_html) {
5161                 return;
5162             }
5163             // only record events every second.
5164             if (t.timer !== false) {
5165                clearTimeout(t.timer);
5166                t.timer = false;
5167             }
5168             t.timer = setTimeout(function() { t.merge = false; }, 1000);
5169             
5170             t.addEvent(t.merge);
5171             t.merge = true; // ignore changes happening every second..
5172         });
5173         },
5174     /**
5175      * Manually add an event.
5176      * Normall called without arguements - and it will just get added to the stack.
5177      * 
5178      */
5179     
5180     addEvent : function(merge)
5181     {
5182         //Roo.log("undomanager +" + (merge ? 'Y':'n'));
5183         // not sure if this should clear the timer 
5184         merge = typeof(merge) == 'undefined' ? false : merge; 
5185         
5186         this.scope.undoManager.transact({
5187             scope : this.scope,
5188             oldHTML: this.current_html,
5189             newHTML: this.scope.innerHTML,
5190             // nothing to execute (content already changed when input is fired)
5191             execute: function() { },
5192             undo: function() {
5193                 this.scope.innerHTML = this.current_html = this.oldHTML;
5194             },
5195             redo: function() {
5196                 this.scope.innerHTML = this.current_html = this.newHTML;
5197             }
5198         }, false); //merge);
5199         
5200         this.merge = merge;
5201         
5202         this.current_html = this.scope.innerHTML;
5203     }
5204     
5205     
5206      
5207     
5208     
5209     
5210 };
5211 /*
5212  * Based on:
5213  * Ext JS Library 1.1.1
5214  * Copyright(c) 2006-2007, Ext JS, LLC.
5215  *
5216  * Originally Released Under LGPL - original licence link has changed is not relivant.
5217  *
5218  * Fork - LGPL
5219  * <script type="text/javascript">
5220  */
5221
5222
5223 // nasty IE9 hack - what a pile of crap that is..
5224
5225  if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
5226     Range.prototype.createContextualFragment = function (html) {
5227         var doc = window.document;
5228         var container = doc.createElement("div");
5229         container.innerHTML = html;
5230         var frag = doc.createDocumentFragment(), n;
5231         while ((n = container.firstChild)) {
5232             frag.appendChild(n);
5233         }
5234         return frag;
5235     };
5236 }
5237
5238 /**
5239  * @class Roo.DomHelper
5240  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
5241  * 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>.
5242  * @static
5243  */
5244 Roo.DomHelper = function(){
5245     var tempTableEl = null;
5246     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
5247     var tableRe = /^table|tbody|tr|td$/i;
5248     var xmlns = {};
5249     // build as innerHTML where available
5250     /** @ignore */
5251     var createHtml = function(o){
5252         if(typeof o == 'string'){
5253             return o;
5254         }
5255         var b = "";
5256         if(!o.tag){
5257             o.tag = "div";
5258         }
5259         b += "<" + o.tag;
5260         for(var attr in o){
5261             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") { continue; }
5262             if(attr == "style"){
5263                 var s = o["style"];
5264                 if(typeof s == "function"){
5265                     s = s.call();
5266                 }
5267                 if(typeof s == "string"){
5268                     b += ' style="' + s + '"';
5269                 }else if(typeof s == "object"){
5270                     b += ' style="';
5271                     for(var key in s){
5272                         if(typeof s[key] != "function"){
5273                             b += key + ":" + s[key] + ";";
5274                         }
5275                     }
5276                     b += '"';
5277                 }
5278             }else{
5279                 if(attr == "cls"){
5280                     b += ' class="' + o["cls"] + '"';
5281                 }else if(attr == "htmlFor"){
5282                     b += ' for="' + o["htmlFor"] + '"';
5283                 }else{
5284                     b += " " + attr + '="' + o[attr] + '"';
5285                 }
5286             }
5287         }
5288         if(emptyTags.test(o.tag)){
5289             b += "/>";
5290         }else{
5291             b += ">";
5292             var cn = o.children || o.cn;
5293             if(cn){
5294                 //http://bugs.kde.org/show_bug.cgi?id=71506
5295                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
5296                     for(var i = 0, len = cn.length; i < len; i++) {
5297                         b += createHtml(cn[i], b);
5298                     }
5299                 }else{
5300                     b += createHtml(cn, b);
5301                 }
5302             }
5303             if(o.html){
5304                 b += o.html;
5305             }
5306             b += "</" + o.tag + ">";
5307         }
5308         return b;
5309     };
5310
5311     // build as dom
5312     /** @ignore */
5313     var createDom = function(o, parentNode){
5314          
5315         // defininition craeted..
5316         var ns = false;
5317         if (o.ns && o.ns != 'html') {
5318                
5319             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
5320                 xmlns[o.ns] = o.xmlns;
5321                 ns = o.xmlns;
5322             }
5323             if (typeof(xmlns[o.ns]) == 'undefined') {
5324                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
5325             }
5326             ns = xmlns[o.ns];
5327         }
5328         
5329         
5330         if (typeof(o) == 'string') {
5331             return parentNode.appendChild(document.createTextNode(o));
5332         }
5333         o.tag = o.tag || div;
5334         if (o.ns && Roo.isIE) {
5335             ns = false;
5336             o.tag = o.ns + ':' + o.tag;
5337             
5338         }
5339         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
5340         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
5341         for(var attr in o){
5342             
5343             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
5344                     attr == "style" || typeof o[attr] == "function") { continue; }
5345                     
5346             if(attr=="cls" && Roo.isIE){
5347                 el.className = o["cls"];
5348             }else{
5349                 if(useSet) { el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);}
5350                 else { 
5351                     el[attr] = o[attr];
5352                 }
5353             }
5354         }
5355         Roo.DomHelper.applyStyles(el, o.style);
5356         var cn = o.children || o.cn;
5357         if(cn){
5358             //http://bugs.kde.org/show_bug.cgi?id=71506
5359              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
5360                 for(var i = 0, len = cn.length; i < len; i++) {
5361                     createDom(cn[i], el);
5362                 }
5363             }else{
5364                 createDom(cn, el);
5365             }
5366         }
5367         if(o.html){
5368             el.innerHTML = o.html;
5369         }
5370         if(parentNode){
5371            parentNode.appendChild(el);
5372         }
5373         return el;
5374     };
5375
5376     var ieTable = function(depth, s, h, e){
5377         tempTableEl.innerHTML = [s, h, e].join('');
5378         var i = -1, el = tempTableEl;
5379         while(++i < depth && el.firstChild){
5380             el = el.firstChild;
5381         }
5382         return el;
5383     };
5384
5385     // kill repeat to save bytes
5386     var ts = '<table>',
5387         te = '</table>',
5388         tbs = ts+'<tbody>',
5389         tbe = '</tbody>'+te,
5390         trs = tbs + '<tr>',
5391         tre = '</tr>'+tbe;
5392
5393     /**
5394      * @ignore
5395      * Nasty code for IE's broken table implementation
5396      */
5397     var insertIntoTable = function(tag, where, el, html){
5398         if(!tempTableEl){
5399             tempTableEl = document.createElement('div');
5400         }
5401         var node;
5402         var before = null;
5403         if(tag == 'td'){
5404             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
5405                 return;
5406             }
5407             if(where == 'beforebegin'){
5408                 before = el;
5409                 el = el.parentNode;
5410             } else{
5411                 before = el.nextSibling;
5412                 el = el.parentNode;
5413             }
5414             node = ieTable(4, trs, html, tre);
5415         }
5416         else if(tag == 'tr'){
5417             if(where == 'beforebegin'){
5418                 before = el;
5419                 el = el.parentNode;
5420                 node = ieTable(3, tbs, html, tbe);
5421             } else if(where == 'afterend'){
5422                 before = el.nextSibling;
5423                 el = el.parentNode;
5424                 node = ieTable(3, tbs, html, tbe);
5425             } else{ // INTO a TR
5426                 if(where == 'afterbegin'){
5427                     before = el.firstChild;
5428                 }
5429                 node = ieTable(4, trs, html, tre);
5430             }
5431         } else if(tag == 'tbody'){
5432             if(where == 'beforebegin'){
5433                 before = el;
5434                 el = el.parentNode;
5435                 node = ieTable(2, ts, html, te);
5436             } else if(where == 'afterend'){
5437                 before = el.nextSibling;
5438                 el = el.parentNode;
5439                 node = ieTable(2, ts, html, te);
5440             } else{
5441                 if(where == 'afterbegin'){
5442                     before = el.firstChild;
5443                 }
5444                 node = ieTable(3, tbs, html, tbe);
5445             }
5446         } else{ // TABLE
5447             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
5448                 return;
5449             }
5450             if(where == 'afterbegin'){
5451                 before = el.firstChild;
5452             }
5453             node = ieTable(2, ts, html, te);
5454         }
5455         el.insertBefore(node, before);
5456         return node;
5457     };
5458     
5459     // this is a bit like the react update code...
5460     // 
5461     
5462     var updateNode = function(from, to)
5463     {
5464         // should we handle non-standard elements?
5465         Roo.log(["UpdateNode" , from, to]);
5466         if (from.nodeType != to.nodeType) {
5467             Roo.log(["ReplaceChild - mismatch notType" , to, from ]);
5468             from.parentNode.replaceChild(to, from);
5469         }
5470         
5471         if (from.nodeType == 3) {
5472             // assume it's text?!
5473             if (from.data == to.data) {
5474                 return;
5475             }
5476             from.data = to.data;
5477             return;
5478         }
5479         
5480         // assume 'to' doesnt have '1/3 nodetypes!
5481         if (from.nodeType !=1 || from.tagName != to.tagName) {
5482             Roo.log(["ReplaceChild" , from, to ]);
5483             from.parentNode.replaceChild(to, from);
5484             return;
5485         }
5486         // compare attributes
5487         var ar = Array.from(from.attributes);
5488         for(var i = 0; i< ar.length;i++) {
5489             if (to.hasAttribute(ar[i].name)) {
5490                 continue;
5491             }
5492             if (ar[i].name == 'id') { // always keep ids?
5493                continue;
5494             }
5495             //if (ar[i].name == 'style') {
5496             //   throw "style removed?";
5497             //}
5498             Roo.log("removeAttribute" + ar[i].name);
5499             from.removeAttribute(ar[i].name);
5500         }
5501         ar = to.attributes;
5502         for(var i = 0; i< ar.length;i++) {
5503             if (from.getAttribute(ar[i].name) == to.getAttribute(ar[i].name)) {
5504                 Roo.log("skipAttribute " + ar[i].name  + '=' + to.getAttribute(ar[i].name));
5505                 continue;
5506             }
5507             Roo.log("updateAttribute " + ar[i].name + '=>' + to.getAttribute(ar[i].name));
5508             from.setAttribute(ar[i].name, to.getAttribute(ar[i].name));
5509         }
5510         // children
5511         var far = Array.from(from.childNodes);
5512         var tar = Array.from(to.childNodes);
5513         // if the lengths are different.. then it's probably a editable content change, rather than
5514         // a change of the block definition..
5515         
5516         // this did notwork , as our rebuilt nodes did not include ID's so did not match at all.
5517          /*if (from.innerHTML == to.innerHTML) {
5518             return;
5519         }
5520         if (far.length != tar.length) {
5521             from.innerHTML = to.innerHTML;
5522             return;
5523         }
5524         */
5525         
5526         for(var i = 0; i < Math.max(tar.length, far.length); i++) {
5527             if (i >= far.length) {
5528                 from.appendChild(tar[i]);
5529                 Roo.log(["add", tar[i]]);
5530                 
5531             } else if ( i  >= tar.length) {
5532                 from.removeChild(far[i]);
5533                 Roo.log(["remove", far[i]]);
5534             } else {
5535                 
5536                 updateNode(far[i], tar[i]);
5537             }    
5538         }
5539         
5540         
5541         
5542         
5543     };
5544     
5545     
5546
5547     return {
5548         /** True to force the use of DOM instead of html fragments @type Boolean */
5549         useDom : false,
5550     
5551         /**
5552          * Returns the markup for the passed Element(s) config
5553          * @param {Object} o The Dom object spec (and children)
5554          * @return {String}
5555          */
5556         markup : function(o){
5557             return createHtml(o);
5558         },
5559     
5560         /**
5561          * Applies a style specification to an element
5562          * @param {String/HTMLElement} el The element to apply styles to
5563          * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
5564          * a function which returns such a specification.
5565          */
5566         applyStyles : function(el, styles){
5567             if(styles){
5568                el = Roo.fly(el);
5569                if(typeof styles == "string"){
5570                    var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
5571                    var matches;
5572                    while ((matches = re.exec(styles)) != null){
5573                        el.setStyle(matches[1], matches[2]);
5574                    }
5575                }else if (typeof styles == "object"){
5576                    for (var style in styles){
5577                       el.setStyle(style, styles[style]);
5578                    }
5579                }else if (typeof styles == "function"){
5580                     Roo.DomHelper.applyStyles(el, styles.call());
5581                }
5582             }
5583         },
5584     
5585         /**
5586          * Inserts an HTML fragment into the Dom
5587          * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
5588          * @param {HTMLElement} el The context element
5589          * @param {String} html The HTML fragmenet
5590          * @return {HTMLElement} The new node
5591          */
5592         insertHtml : function(where, el, html){
5593             where = where.toLowerCase();
5594             if(el.insertAdjacentHTML){
5595                 if(tableRe.test(el.tagName)){
5596                     var rs;
5597                     if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
5598                         return rs;
5599                     }
5600                 }
5601                 switch(where){
5602                     case "beforebegin":
5603                         el.insertAdjacentHTML('BeforeBegin', html);
5604                         return el.previousSibling;
5605                     case "afterbegin":
5606                         el.insertAdjacentHTML('AfterBegin', html);
5607                         return el.firstChild;
5608                     case "beforeend":
5609                         el.insertAdjacentHTML('BeforeEnd', html);
5610                         return el.lastChild;
5611                     case "afterend":
5612                         el.insertAdjacentHTML('AfterEnd', html);
5613                         return el.nextSibling;
5614                 }
5615                 throw 'Illegal insertion point -> "' + where + '"';
5616             }
5617             var range = el.ownerDocument.createRange();
5618             var frag;
5619             switch(where){
5620                  case "beforebegin":
5621                     range.setStartBefore(el);
5622                     frag = range.createContextualFragment(html);
5623                     el.parentNode.insertBefore(frag, el);
5624                     return el.previousSibling;
5625                  case "afterbegin":
5626                     if(el.firstChild){
5627                         range.setStartBefore(el.firstChild);
5628                         frag = range.createContextualFragment(html);
5629                         el.insertBefore(frag, el.firstChild);
5630                         return el.firstChild;
5631                     }else{
5632                         el.innerHTML = html;
5633                         return el.firstChild;
5634                     }
5635                 case "beforeend":
5636                     if(el.lastChild){
5637                         range.setStartAfter(el.lastChild);
5638                         frag = range.createContextualFragment(html);
5639                         el.appendChild(frag);
5640                         return el.lastChild;
5641                     }else{
5642                         el.innerHTML = html;
5643                         return el.lastChild;
5644                     }
5645                 case "afterend":
5646                     range.setStartAfter(el);
5647                     frag = range.createContextualFragment(html);
5648                     el.parentNode.insertBefore(frag, el.nextSibling);
5649                     return el.nextSibling;
5650                 }
5651                 throw 'Illegal insertion point -> "' + where + '"';
5652         },
5653     
5654         /**
5655          * Creates new Dom element(s) and inserts them before el
5656          * @param {String/HTMLElement/Element} el The context element
5657          * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5658          * @param {Boolean} returnElement (optional) true to return a Roo.Element
5659          * @return {HTMLElement/Roo.Element} The new node
5660          */
5661         insertBefore : function(el, o, returnElement){
5662             return this.doInsert(el, o, returnElement, "beforeBegin");
5663         },
5664     
5665         /**
5666          * Creates new Dom element(s) and inserts them after el
5667          * @param {String/HTMLElement/Element} el The context element
5668          * @param {Object} o The Dom object spec (and children)
5669          * @param {Boolean} returnElement (optional) true to return a Roo.Element
5670          * @return {HTMLElement/Roo.Element} The new node
5671          */
5672         insertAfter : function(el, o, returnElement){
5673             return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
5674         },
5675     
5676         /**
5677          * Creates new Dom element(s) and inserts them as the first child of el
5678          * @param {String/HTMLElement/Element} el The context element
5679          * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5680          * @param {Boolean} returnElement (optional) true to return a Roo.Element
5681          * @return {HTMLElement/Roo.Element} The new node
5682          */
5683         insertFirst : function(el, o, returnElement){
5684             return this.doInsert(el, o, returnElement, "afterBegin");
5685         },
5686     
5687         // private
5688         doInsert : function(el, o, returnElement, pos, sibling){
5689             el = Roo.getDom(el);
5690             var newNode;
5691             if(this.useDom || o.ns){
5692                 newNode = createDom(o, null);
5693                 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
5694             }else{
5695                 var html = createHtml(o);
5696                 newNode = this.insertHtml(pos, el, html);
5697             }
5698             return returnElement ? Roo.get(newNode, true) : newNode;
5699         },
5700     
5701         /**
5702          * Creates new Dom element(s) and appends them to el
5703          * @param {String/HTMLElement/Element} el The context element
5704          * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5705          * @param {Boolean} returnElement (optional) true to return a Roo.Element
5706          * @return {HTMLElement/Roo.Element} The new node
5707          */
5708         append : function(el, o, returnElement){
5709             el = Roo.getDom(el);
5710             var newNode;
5711             if(this.useDom || o.ns){
5712                 newNode = createDom(o, null);
5713                 el.appendChild(newNode);
5714             }else{
5715                 var html = createHtml(o);
5716                 newNode = this.insertHtml("beforeEnd", el, html);
5717             }
5718             return returnElement ? Roo.get(newNode, true) : newNode;
5719         },
5720     
5721         /**
5722          * Creates new Dom element(s) and overwrites the contents of el with them
5723          * @param {String/HTMLElement/Element} el The context element
5724          * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5725          * @param {Boolean} returnElement (optional) true to return a Roo.Element
5726          * @return {HTMLElement/Roo.Element} The new node
5727          */
5728         overwrite : function(el, o, returnElement)
5729         {
5730             el = Roo.getDom(el);
5731             if (o.ns) {
5732               
5733                 while (el.childNodes.length) {
5734                     el.removeChild(el.firstChild);
5735                 }
5736                 createDom(o, el);
5737             } else {
5738                 el.innerHTML = createHtml(o);   
5739             }
5740             
5741             return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
5742         },
5743     
5744         /**
5745          * Creates a new Roo.DomHelper.Template from the Dom object spec
5746          * @param {Object} o The Dom object spec (and children)
5747          * @return {Roo.DomHelper.Template} The new template
5748          */
5749         createTemplate : function(o){
5750             var html = createHtml(o);
5751             return new Roo.Template(html);
5752         },
5753          /**
5754          * Updates the first element with the spec from the o (replacing if necessary)
5755          * This iterates through the children, and updates attributes / children etc..
5756          * @param {String/HTMLElement/Element} el The context element
5757          * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5758          */
5759         
5760         update : function(el, o)
5761         {
5762             updateNode(Roo.getDom(el), createDom(o));
5763             
5764         }
5765         
5766         
5767     };
5768 }();
5769 /*
5770  * Based on:
5771  * Ext JS Library 1.1.1
5772  * Copyright(c) 2006-2007, Ext JS, LLC.
5773  *
5774  * Originally Released Under LGPL - original licence link has changed is not relivant.
5775  *
5776  * Fork - LGPL
5777  * <script type="text/javascript">
5778  */
5779  
5780 /**
5781 * @class Roo.Template
5782 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
5783 * For a list of available format functions, see {@link Roo.util.Format}.<br />
5784 * Usage:
5785 <pre><code>
5786 var t = new Roo.Template({
5787     html :  '&lt;div name="{id}"&gt;' + 
5788         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
5789         '&lt;/div&gt;',
5790     myformat: function (value, allValues) {
5791         return 'XX' + value;
5792     }
5793 });
5794 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
5795 </code></pre>
5796 * For more information see this blog post with examples:
5797 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
5798      - Create Elements using DOM, HTML fragments and Templates</a>. 
5799 * @constructor
5800 * @param {Object} cfg - Configuration object.
5801 */
5802 Roo.Template = function(cfg){
5803     // BC!
5804     if(cfg instanceof Array){
5805         cfg = cfg.join("");
5806     }else if(arguments.length > 1){
5807         cfg = Array.prototype.join.call(arguments, "");
5808     }
5809     
5810     
5811     if (typeof(cfg) == 'object') {
5812         Roo.apply(this,cfg)
5813     } else {
5814         // bc
5815         this.html = cfg;
5816     }
5817     if (this.url) {
5818         this.load();
5819     }
5820     
5821 };
5822 Roo.Template.prototype = {
5823     
5824     /**
5825      * @cfg {Function} onLoad Called after the template has been loaded and complied (usually from a remove source)
5826      */
5827     onLoad : false,
5828     
5829     
5830     /**
5831      * @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..
5832      *                    it should be fixed so that template is observable...
5833      */
5834     url : false,
5835     /**
5836      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
5837      */
5838     html : '',
5839     
5840     
5841     compiled : false,
5842     loaded : false,
5843     /**
5844      * Returns an HTML fragment of this template with the specified values applied.
5845      * @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'})
5846      * @return {String} The HTML fragment
5847      */
5848     
5849    
5850     
5851     applyTemplate : function(values){
5852         //Roo.log(["applyTemplate", values]);
5853         try {
5854            
5855             if(this.compiled){
5856                 return this.compiled(values);
5857             }
5858             var useF = this.disableFormats !== true;
5859             var fm = Roo.util.Format, tpl = this;
5860             var fn = function(m, name, format, args){
5861                 if(format && useF){
5862                     if(format.substr(0, 5) == "this."){
5863                         return tpl.call(format.substr(5), values[name], values);
5864                     }else{
5865                         if(args){
5866                             // quoted values are required for strings in compiled templates, 
5867                             // but for non compiled we need to strip them
5868                             // quoted reversed for jsmin
5869                             var re = /^\s*['"](.*)["']\s*$/;
5870                             args = args.split(',');
5871                             for(var i = 0, len = args.length; i < len; i++){
5872                                 args[i] = args[i].replace(re, "$1");
5873                             }
5874                             args = [values[name]].concat(args);
5875                         }else{
5876                             args = [values[name]];
5877                         }
5878                         return fm[format].apply(fm, args);
5879                     }
5880                 }else{
5881                     return values[name] !== undefined ? values[name] : "";
5882                 }
5883             };
5884             return this.html.replace(this.re, fn);
5885         } catch (e) {
5886             Roo.log(e);
5887             throw e;
5888         }
5889          
5890     },
5891     
5892     loading : false,
5893       
5894     load : function ()
5895     {
5896          
5897         if (this.loading) {
5898             return;
5899         }
5900         var _t = this;
5901         
5902         this.loading = true;
5903         this.compiled = false;
5904         
5905         var cx = new Roo.data.Connection();
5906         cx.request({
5907             url : this.url,
5908             method : 'GET',
5909             success : function (response) {
5910                 _t.loading = false;
5911                 _t.url = false;
5912                 
5913                 _t.set(response.responseText,true);
5914                 _t.loaded = true;
5915                 if (_t.onLoad) {
5916                     _t.onLoad();
5917                 }
5918              },
5919             failure : function(response) {
5920                 Roo.log("Template failed to load from " + _t.url);
5921                 _t.loading = false;
5922             }
5923         });
5924     },
5925
5926     /**
5927      * Sets the HTML used as the template and optionally compiles it.
5928      * @param {String} html
5929      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
5930      * @return {Roo.Template} this
5931      */
5932     set : function(html, compile){
5933         this.html = html;
5934         this.compiled = false;
5935         if(compile){
5936             this.compile();
5937         }
5938         return this;
5939     },
5940     
5941     /**
5942      * True to disable format functions (defaults to false)
5943      * @type Boolean
5944      */
5945     disableFormats : false,
5946     
5947     /**
5948     * The regular expression used to match template variables 
5949     * @type RegExp
5950     * @property 
5951     */
5952     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
5953     
5954     /**
5955      * Compiles the template into an internal function, eliminating the RegEx overhead.
5956      * @return {Roo.Template} this
5957      */
5958     compile : function(){
5959         var fm = Roo.util.Format;
5960         var useF = this.disableFormats !== true;
5961         var sep = Roo.isGecko ? "+" : ",";
5962         var fn = function(m, name, format, args){
5963             if(format && useF){
5964                 args = args ? ',' + args : "";
5965                 if(format.substr(0, 5) != "this."){
5966                     format = "fm." + format + '(';
5967                 }else{
5968                     format = 'this.call("'+ format.substr(5) + '", ';
5969                     args = ", values";
5970                 }
5971             }else{
5972                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
5973             }
5974             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
5975         };
5976         var body;
5977         // branched to use + in gecko and [].join() in others
5978         if(Roo.isGecko){
5979             body = "this.compiled = function(values){ return '" +
5980                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
5981                     "';};";
5982         }else{
5983             body = ["this.compiled = function(values){ return ['"];
5984             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
5985             body.push("'].join('');};");
5986             body = body.join('');
5987         }
5988         /**
5989          * eval:var:values
5990          * eval:var:fm
5991          */
5992         eval(body);
5993         return this;
5994     },
5995     
5996     // private function used to call members
5997     call : function(fnName, value, allValues){
5998         return this[fnName](value, allValues);
5999     },
6000     
6001     /**
6002      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
6003      * @param {String/HTMLElement/Roo.Element} el The context element
6004      * @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'})
6005      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
6006      * @return {HTMLElement/Roo.Element} The new node or Element
6007      */
6008     insertFirst: function(el, values, returnElement){
6009         return this.doInsert('afterBegin', el, values, returnElement);
6010     },
6011
6012     /**
6013      * Applies the supplied values to the template and inserts the new node(s) before el.
6014      * @param {String/HTMLElement/Roo.Element} el The context element
6015      * @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'})
6016      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
6017      * @return {HTMLElement/Roo.Element} The new node or Element
6018      */
6019     insertBefore: function(el, values, returnElement){
6020         return this.doInsert('beforeBegin', el, values, returnElement);
6021     },
6022
6023     /**
6024      * Applies the supplied values to the template and inserts the new node(s) after el.
6025      * @param {String/HTMLElement/Roo.Element} el The context element
6026      * @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'})
6027      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
6028      * @return {HTMLElement/Roo.Element} The new node or Element
6029      */
6030     insertAfter : function(el, values, returnElement){
6031         return this.doInsert('afterEnd', el, values, returnElement);
6032     },
6033     
6034     /**
6035      * Applies the supplied values to the template and appends the new node(s) to el.
6036      * @param {String/HTMLElement/Roo.Element} el The context element
6037      * @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'})
6038      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
6039      * @return {HTMLElement/Roo.Element} The new node or Element
6040      */
6041     append : function(el, values, returnElement){
6042         return this.doInsert('beforeEnd', el, values, returnElement);
6043     },
6044
6045     doInsert : function(where, el, values, returnEl){
6046         el = Roo.getDom(el);
6047         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
6048         return returnEl ? Roo.get(newNode, true) : newNode;
6049     },
6050
6051     /**
6052      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
6053      * @param {String/HTMLElement/Roo.Element} el The context element
6054      * @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'})
6055      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
6056      * @return {HTMLElement/Roo.Element} The new node or Element
6057      */
6058     overwrite : function(el, values, returnElement){
6059         el = Roo.getDom(el);
6060         el.innerHTML = this.applyTemplate(values);
6061         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
6062     }
6063 };
6064 /**
6065  * Alias for {@link #applyTemplate}
6066  * @method
6067  */
6068 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
6069
6070 // backwards compat
6071 Roo.DomHelper.Template = Roo.Template;
6072
6073 /**
6074  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
6075  * @param {String/HTMLElement} el A DOM element or its id
6076  * @returns {Roo.Template} The created template
6077  * @static
6078  */
6079 Roo.Template.from = function(el){
6080     el = Roo.getDom(el);
6081     return new Roo.Template(el.value || el.innerHTML);
6082 };/*
6083  * Based on:
6084  * Ext JS Library 1.1.1
6085  * Copyright(c) 2006-2007, Ext JS, LLC.
6086  *
6087  * Originally Released Under LGPL - original licence link has changed is not relivant.
6088  *
6089  * Fork - LGPL
6090  * <script type="text/javascript">
6091  */
6092  
6093
6094 /*
6095  * This is code is also distributed under MIT license for use
6096  * with jQuery and prototype JavaScript libraries.
6097  */
6098 /**
6099  * @class Roo.DomQuery
6100 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).
6101 <p>
6102 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>
6103
6104 <p>
6105 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.
6106 </p>
6107 <h4>Element Selectors:</h4>
6108 <ul class="list">
6109     <li> <b>*</b> any element</li>
6110     <li> <b>E</b> an element with the tag E</li>
6111     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
6112     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
6113     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
6114     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
6115 </ul>
6116 <h4>Attribute Selectors:</h4>
6117 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
6118 <ul class="list">
6119     <li> <b>E[foo]</b> has an attribute "foo"</li>
6120     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
6121     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
6122     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
6123     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
6124     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
6125     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
6126 </ul>
6127 <h4>Pseudo Classes:</h4>
6128 <ul class="list">
6129     <li> <b>E:first-child</b> E is the first child of its parent</li>
6130     <li> <b>E:last-child</b> E is the last child of its parent</li>
6131     <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>
6132     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
6133     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
6134     <li> <b>E:only-child</b> E is the only child of its parent</li>
6135     <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>
6136     <li> <b>E:first</b> the first E in the resultset</li>
6137     <li> <b>E:last</b> the last E in the resultset</li>
6138     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
6139     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
6140     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
6141     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
6142     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
6143     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
6144     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
6145     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
6146     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
6147 </ul>
6148 <h4>CSS Value Selectors:</h4>
6149 <ul class="list">
6150     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
6151     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
6152     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
6153     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
6154     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
6155     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
6156 </ul>
6157  * @static
6158  */
6159 Roo.DomQuery = function(){
6160     var cache = {}, simpleCache = {}, valueCache = {};
6161     var nonSpace = /\S/;
6162     var trimRe = /^\s+|\s+$/g;
6163     var tplRe = /\{(\d+)\}/g;
6164     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
6165     var tagTokenRe = /^(#)?([\w-\*]+)/;
6166     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
6167
6168     function child(p, index){
6169         var i = 0;
6170         var n = p.firstChild;
6171         while(n){
6172             if(n.nodeType == 1){
6173                if(++i == index){
6174                    return n;
6175                }
6176             }
6177             n = n.nextSibling;
6178         }
6179         return null;
6180     };
6181
6182     function next(n){
6183         while((n = n.nextSibling) && n.nodeType != 1);
6184         return n;
6185     };
6186
6187     function prev(n){
6188         while((n = n.previousSibling) && n.nodeType != 1);
6189         return n;
6190     };
6191
6192     function children(d){
6193         var n = d.firstChild, ni = -1;
6194             while(n){
6195                 var nx = n.nextSibling;
6196                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
6197                     d.removeChild(n);
6198                 }else{
6199                     n.nodeIndex = ++ni;
6200                 }
6201                 n = nx;
6202             }
6203             return this;
6204         };
6205
6206     function byClassName(c, a, v){
6207         if(!v){
6208             return c;
6209         }
6210         var r = [], ri = -1, cn;
6211         for(var i = 0, ci; ci = c[i]; i++){
6212             
6213             
6214             if((' '+
6215                 ( (ci instanceof SVGElement) ? ci.className.baseVal : ci.className)
6216                  +' ').indexOf(v) != -1){
6217                 r[++ri] = ci;
6218             }
6219         }
6220         return r;
6221     };
6222
6223     function attrValue(n, attr){
6224         if(!n.tagName && typeof n.length != "undefined"){
6225             n = n[0];
6226         }
6227         if(!n){
6228             return null;
6229         }
6230         if(attr == "for"){
6231             return n.htmlFor;
6232         }
6233         if(attr == "class" || attr == "className"){
6234             return (n instanceof SVGElement) ? n.className.baseVal : n.className;
6235         }
6236         return n.getAttribute(attr) || n[attr];
6237
6238     };
6239
6240     function getNodes(ns, mode, tagName){
6241         var result = [], ri = -1, cs;
6242         if(!ns){
6243             return result;
6244         }
6245         tagName = tagName || "*";
6246         if(typeof ns.getElementsByTagName != "undefined"){
6247             ns = [ns];
6248         }
6249         if(!mode){
6250             for(var i = 0, ni; ni = ns[i]; i++){
6251                 cs = ni.getElementsByTagName(tagName);
6252                 for(var j = 0, ci; ci = cs[j]; j++){
6253                     result[++ri] = ci;
6254                 }
6255             }
6256         }else if(mode == "/" || mode == ">"){
6257             var utag = tagName.toUpperCase();
6258             for(var i = 0, ni, cn; ni = ns[i]; i++){
6259                 cn = ni.children || ni.childNodes;
6260                 for(var j = 0, cj; cj = cn[j]; j++){
6261                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
6262                         result[++ri] = cj;
6263                     }
6264                 }
6265             }
6266         }else if(mode == "+"){
6267             var utag = tagName.toUpperCase();
6268             for(var i = 0, n; n = ns[i]; i++){
6269                 while((n = n.nextSibling) && n.nodeType != 1);
6270                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
6271                     result[++ri] = n;
6272                 }
6273             }
6274         }else if(mode == "~"){
6275             for(var i = 0, n; n = ns[i]; i++){
6276                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
6277                 if(n){
6278                     result[++ri] = n;
6279                 }
6280             }
6281         }
6282         return result;
6283     };
6284
6285     function concat(a, b){
6286         if(b.slice){
6287             return a.concat(b);
6288         }
6289         for(var i = 0, l = b.length; i < l; i++){
6290             a[a.length] = b[i];
6291         }
6292         return a;
6293     }
6294
6295     function byTag(cs, tagName){
6296         if(cs.tagName || cs == document){
6297             cs = [cs];
6298         }
6299         if(!tagName){
6300             return cs;
6301         }
6302         var r = [], ri = -1;
6303         tagName = tagName.toLowerCase();
6304         for(var i = 0, ci; ci = cs[i]; i++){
6305             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
6306                 r[++ri] = ci;
6307             }
6308         }
6309         return r;
6310     };
6311
6312     function byId(cs, attr, id){
6313         if(cs.tagName || cs == document){
6314             cs = [cs];
6315         }
6316         if(!id){
6317             return cs;
6318         }
6319         var r = [], ri = -1;
6320         for(var i = 0,ci; ci = cs[i]; i++){
6321             if(ci && ci.id == id){
6322                 r[++ri] = ci;
6323                 return r;
6324             }
6325         }
6326         return r;
6327     };
6328
6329     function byAttribute(cs, attr, value, op, custom){
6330         var r = [], ri = -1, st = custom=="{";
6331         var f = Roo.DomQuery.operators[op];
6332         for(var i = 0, ci; ci = cs[i]; i++){
6333             var a;
6334             if(st){
6335                 a = Roo.DomQuery.getStyle(ci, attr);
6336             }
6337             else if(attr == "class" || attr == "className"){
6338                 a = (ci instanceof SVGElement) ? ci.className.baseVal : ci.className;
6339             }else if(attr == "for"){
6340                 a = ci.htmlFor;
6341             }else if(attr == "href"){
6342                 a = ci.getAttribute("href", 2);
6343             }else{
6344                 a = ci.getAttribute(attr);
6345             }
6346             if((f && f(a, value)) || (!f && a)){
6347                 r[++ri] = ci;
6348             }
6349         }
6350         return r;
6351     };
6352
6353     function byPseudo(cs, name, value){
6354         return Roo.DomQuery.pseudos[name](cs, value);
6355     };
6356
6357     // This is for IE MSXML which does not support expandos.
6358     // IE runs the same speed using setAttribute, however FF slows way down
6359     // and Safari completely fails so they need to continue to use expandos.
6360     var isIE = window.ActiveXObject ? true : false;
6361
6362     // this eval is stop the compressor from
6363     // renaming the variable to something shorter
6364     
6365     /** eval:var:batch */
6366     var batch = 30803; 
6367
6368     var key = 30803;
6369
6370     function nodupIEXml(cs){
6371         var d = ++key;
6372         cs[0].setAttribute("_nodup", d);
6373         var r = [cs[0]];
6374         for(var i = 1, len = cs.length; i < len; i++){
6375             var c = cs[i];
6376             if(!c.getAttribute("_nodup") != d){
6377                 c.setAttribute("_nodup", d);
6378                 r[r.length] = c;
6379             }
6380         }
6381         for(var i = 0, len = cs.length; i < len; i++){
6382             cs[i].removeAttribute("_nodup");
6383         }
6384         return r;
6385     }
6386
6387     function nodup(cs){
6388         if(!cs){
6389             return [];
6390         }
6391         var len = cs.length, c, i, r = cs, cj, ri = -1;
6392         if(!len || typeof cs.nodeType != "undefined" || len == 1){
6393             return cs;
6394         }
6395         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
6396             return nodupIEXml(cs);
6397         }
6398         var d = ++key;
6399         cs[0]._nodup = d;
6400         for(i = 1; c = cs[i]; i++){
6401             if(c._nodup != d){
6402                 c._nodup = d;
6403             }else{
6404                 r = [];
6405                 for(var j = 0; j < i; j++){
6406                     r[++ri] = cs[j];
6407                 }
6408                 for(j = i+1; cj = cs[j]; j++){
6409                     if(cj._nodup != d){
6410                         cj._nodup = d;
6411                         r[++ri] = cj;
6412                     }
6413                 }
6414                 return r;
6415             }
6416         }
6417         return r;
6418     }
6419
6420     function quickDiffIEXml(c1, c2){
6421         var d = ++key;
6422         for(var i = 0, len = c1.length; i < len; i++){
6423             c1[i].setAttribute("_qdiff", d);
6424         }
6425         var r = [];
6426         for(var i = 0, len = c2.length; i < len; i++){
6427             if(c2[i].getAttribute("_qdiff") != d){
6428                 r[r.length] = c2[i];
6429             }
6430         }
6431         for(var i = 0, len = c1.length; i < len; i++){
6432            c1[i].removeAttribute("_qdiff");
6433         }
6434         return r;
6435     }
6436
6437     function quickDiff(c1, c2){
6438         var len1 = c1.length;
6439         if(!len1){
6440             return c2;
6441         }
6442         if(isIE && c1[0].selectSingleNode){
6443             return quickDiffIEXml(c1, c2);
6444         }
6445         var d = ++key;
6446         for(var i = 0; i < len1; i++){
6447             c1[i]._qdiff = d;
6448         }
6449         var r = [];
6450         for(var i = 0, len = c2.length; i < len; i++){
6451             if(c2[i]._qdiff != d){
6452                 r[r.length] = c2[i];
6453             }
6454         }
6455         return r;
6456     }
6457
6458     function quickId(ns, mode, root, id){
6459         if(ns == root){
6460            var d = root.ownerDocument || root;
6461            return d.getElementById(id);
6462         }
6463         ns = getNodes(ns, mode, "*");
6464         return byId(ns, null, id);
6465     }
6466
6467     return {
6468         getStyle : function(el, name){
6469             return Roo.fly(el).getStyle(name);
6470         },
6471         /**
6472          * Compiles a selector/xpath query into a reusable function. The returned function
6473          * takes one parameter "root" (optional), which is the context node from where the query should start.
6474          * @param {String} selector The selector/xpath query
6475          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
6476          * @return {Function}
6477          */
6478         compile : function(path, type){
6479             type = type || "select";
6480             
6481             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
6482             var q = path, mode, lq;
6483             var tk = Roo.DomQuery.matchers;
6484             var tklen = tk.length;
6485             var mm;
6486
6487             // accept leading mode switch
6488             var lmode = q.match(modeRe);
6489             if(lmode && lmode[1]){
6490                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
6491                 q = q.replace(lmode[1], "");
6492             }
6493             // strip leading slashes
6494             while(path.substr(0, 1)=="/"){
6495                 path = path.substr(1);
6496             }
6497
6498             while(q && lq != q){
6499                 lq = q;
6500                 var tm = q.match(tagTokenRe);
6501                 if(type == "select"){
6502                     if(tm){
6503                         if(tm[1] == "#"){
6504                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
6505                         }else{
6506                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
6507                         }
6508                         q = q.replace(tm[0], "");
6509                     }else if(q.substr(0, 1) != '@'){
6510                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
6511                     }
6512                 }else{
6513                     if(tm){
6514                         if(tm[1] == "#"){
6515                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
6516                         }else{
6517                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
6518                         }
6519                         q = q.replace(tm[0], "");
6520                     }
6521                 }
6522                 while(!(mm = q.match(modeRe))){
6523                     var matched = false;
6524                     for(var j = 0; j < tklen; j++){
6525                         var t = tk[j];
6526                         var m = q.match(t.re);
6527                         if(m){
6528                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
6529                                                     return m[i];
6530                                                 });
6531                             q = q.replace(m[0], "");
6532                             matched = true;
6533                             break;
6534                         }
6535                     }
6536                     // prevent infinite loop on bad selector
6537                     if(!matched){
6538                         throw 'Error parsing selector, parsing failed at "' + q + '"';
6539                     }
6540                 }
6541                 if(mm[1]){
6542                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
6543                     q = q.replace(mm[1], "");
6544                 }
6545             }
6546             fn[fn.length] = "return nodup(n);\n}";
6547             
6548              /** 
6549               * list of variables that need from compression as they are used by eval.
6550              *  eval:var:batch 
6551              *  eval:var:nodup
6552              *  eval:var:byTag
6553              *  eval:var:ById
6554              *  eval:var:getNodes
6555              *  eval:var:quickId
6556              *  eval:var:mode
6557              *  eval:var:root
6558              *  eval:var:n
6559              *  eval:var:byClassName
6560              *  eval:var:byPseudo
6561              *  eval:var:byAttribute
6562              *  eval:var:attrValue
6563              * 
6564              **/ 
6565             eval(fn.join(""));
6566             return f;
6567         },
6568
6569         /**
6570          * Selects a group of elements.
6571          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
6572          * @param {Node} root (optional) The start of the query (defaults to document).
6573          * @return {Array}
6574          */
6575         select : function(path, root, type){
6576             if(!root || root == document){
6577                 root = document;
6578             }
6579             if(typeof root == "string"){
6580                 root = document.getElementById(root);
6581             }
6582             var paths = path.split(",");
6583             var results = [];
6584             for(var i = 0, len = paths.length; i < len; i++){
6585                 var p = paths[i].replace(trimRe, "");
6586                 if(!cache[p]){
6587                     cache[p] = Roo.DomQuery.compile(p);
6588                     if(!cache[p]){
6589                         throw p + " is not a valid selector";
6590                     }
6591                 }
6592                 var result = cache[p](root);
6593                 if(result && result != document){
6594                     results = results.concat(result);
6595                 }
6596             }
6597             if(paths.length > 1){
6598                 return nodup(results);
6599             }
6600             return results;
6601         },
6602
6603         /**
6604          * Selects a single element.
6605          * @param {String} selector The selector/xpath query
6606          * @param {Node} root (optional) The start of the query (defaults to document).
6607          * @return {Element}
6608          */
6609         selectNode : function(path, root){
6610             return Roo.DomQuery.select(path, root)[0];
6611         },
6612
6613         /**
6614          * Selects the value of a node, optionally replacing null with the defaultValue.
6615          * @param {String} selector The selector/xpath query
6616          * @param {Node} root (optional) The start of the query (defaults to document).
6617          * @param {String} defaultValue
6618          */
6619         selectValue : function(path, root, defaultValue){
6620             path = path.replace(trimRe, "");
6621             if(!valueCache[path]){
6622                 valueCache[path] = Roo.DomQuery.compile(path, "select");
6623             }
6624             var n = valueCache[path](root);
6625             n = n[0] ? n[0] : n;
6626             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
6627             return ((v === null||v === undefined||v==='') ? defaultValue : v);
6628         },
6629
6630         /**
6631          * Selects the value of a node, parsing integers and floats.
6632          * @param {String} selector The selector/xpath query
6633          * @param {Node} root (optional) The start of the query (defaults to document).
6634          * @param {Number} defaultValue
6635          * @return {Number}
6636          */
6637         selectNumber : function(path, root, defaultValue){
6638             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
6639             return parseFloat(v);
6640         },
6641
6642         /**
6643          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
6644          * @param {String/HTMLElement/Array} el An element id, element or array of elements
6645          * @param {String} selector The simple selector to test
6646          * @return {Boolean}
6647          */
6648         is : function(el, ss){
6649             if(typeof el == "string"){
6650                 el = document.getElementById(el);
6651             }
6652             var isArray = (el instanceof Array);
6653             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
6654             return isArray ? (result.length == el.length) : (result.length > 0);
6655         },
6656
6657         /**
6658          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
6659          * @param {Array} el An array of elements to filter
6660          * @param {String} selector The simple selector to test
6661          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
6662          * the selector instead of the ones that match
6663          * @return {Array}
6664          */
6665         filter : function(els, ss, nonMatches){
6666             ss = ss.replace(trimRe, "");
6667             if(!simpleCache[ss]){
6668                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
6669             }
6670             var result = simpleCache[ss](els);
6671             return nonMatches ? quickDiff(result, els) : result;
6672         },
6673
6674         /**
6675          * Collection of matching regular expressions and code snippets.
6676          */
6677         matchers : [{
6678                 re: /^\.([\w-]+)/,
6679                 select: 'n = byClassName(n, null, " {1} ");'
6680             }, {
6681                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
6682                 select: 'n = byPseudo(n, "{1}", "{2}");'
6683             },{
6684                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
6685                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
6686             }, {
6687                 re: /^#([\w-]+)/,
6688                 select: 'n = byId(n, null, "{1}");'
6689             },{
6690                 re: /^@([\w-]+)/,
6691                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
6692             }
6693         ],
6694
6695         /**
6696          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
6697          * 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;.
6698          */
6699         operators : {
6700             "=" : function(a, v){
6701                 return a == v;
6702             },
6703             "!=" : function(a, v){
6704                 return a != v;
6705             },
6706             "^=" : function(a, v){
6707                 return a && a.substr(0, v.length) == v;
6708             },
6709             "$=" : function(a, v){
6710                 return a && a.substr(a.length-v.length) == v;
6711             },
6712             "*=" : function(a, v){
6713                 return a && a.indexOf(v) !== -1;
6714             },
6715             "%=" : function(a, v){
6716                 return (a % v) == 0;
6717             },
6718             "|=" : function(a, v){
6719                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
6720             },
6721             "~=" : function(a, v){
6722                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
6723             }
6724         },
6725
6726         /**
6727          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
6728          * and the argument (if any) supplied in the selector.
6729          */
6730         pseudos : {
6731             "first-child" : function(c){
6732                 var r = [], ri = -1, n;
6733                 for(var i = 0, ci; ci = n = c[i]; i++){
6734                     while((n = n.previousSibling) && n.nodeType != 1);
6735                     if(!n){
6736                         r[++ri] = ci;
6737                     }
6738                 }
6739                 return r;
6740             },
6741
6742             "last-child" : function(c){
6743                 var r = [], ri = -1, n;
6744                 for(var i = 0, ci; ci = n = c[i]; i++){
6745                     while((n = n.nextSibling) && n.nodeType != 1);
6746                     if(!n){
6747                         r[++ri] = ci;
6748                     }
6749                 }
6750                 return r;
6751             },
6752
6753             "nth-child" : function(c, a) {
6754                 var r = [], ri = -1;
6755                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
6756                 var f = (m[1] || 1) - 0, l = m[2] - 0;
6757                 for(var i = 0, n; n = c[i]; i++){
6758                     var pn = n.parentNode;
6759                     if (batch != pn._batch) {
6760                         var j = 0;
6761                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
6762                             if(cn.nodeType == 1){
6763                                cn.nodeIndex = ++j;
6764                             }
6765                         }
6766                         pn._batch = batch;
6767                     }
6768                     if (f == 1) {
6769                         if (l == 0 || n.nodeIndex == l){
6770                             r[++ri] = n;
6771                         }
6772                     } else if ((n.nodeIndex + l) % f == 0){
6773                         r[++ri] = n;
6774                     }
6775                 }
6776
6777                 return r;
6778             },
6779
6780             "only-child" : function(c){
6781                 var r = [], ri = -1;;
6782                 for(var i = 0, ci; ci = c[i]; i++){
6783                     if(!prev(ci) && !next(ci)){
6784                         r[++ri] = ci;
6785                     }
6786                 }
6787                 return r;
6788             },
6789
6790             "empty" : function(c){
6791                 var r = [], ri = -1;
6792                 for(var i = 0, ci; ci = c[i]; i++){
6793                     var cns = ci.childNodes, j = 0, cn, empty = true;
6794                     while(cn = cns[j]){
6795                         ++j;
6796                         if(cn.nodeType == 1 || cn.nodeType == 3){
6797                             empty = false;
6798                             break;
6799                         }
6800                     }
6801                     if(empty){
6802                         r[++ri] = ci;
6803                     }
6804                 }
6805                 return r;
6806             },
6807
6808             "contains" : function(c, v){
6809                 var r = [], ri = -1;
6810                 for(var i = 0, ci; ci = c[i]; i++){
6811                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
6812                         r[++ri] = ci;
6813                     }
6814                 }
6815                 return r;
6816             },
6817
6818             "nodeValue" : function(c, v){
6819                 var r = [], ri = -1;
6820                 for(var i = 0, ci; ci = c[i]; i++){
6821                     if(ci.firstChild && ci.firstChild.nodeValue == v){
6822                         r[++ri] = ci;
6823                     }
6824                 }
6825                 return r;
6826             },
6827
6828             "checked" : function(c){
6829                 var r = [], ri = -1;
6830                 for(var i = 0, ci; ci = c[i]; i++){
6831                     if(ci.checked == true){
6832                         r[++ri] = ci;
6833                     }
6834                 }
6835                 return r;
6836             },
6837
6838             "not" : function(c, ss){
6839                 return Roo.DomQuery.filter(c, ss, true);
6840             },
6841
6842             "odd" : function(c){
6843                 return this["nth-child"](c, "odd");
6844             },
6845
6846             "even" : function(c){
6847                 return this["nth-child"](c, "even");
6848             },
6849
6850             "nth" : function(c, a){
6851                 return c[a-1] || [];
6852             },
6853
6854             "first" : function(c){
6855                 return c[0] || [];
6856             },
6857
6858             "last" : function(c){
6859                 return c[c.length-1] || [];
6860             },
6861
6862             "has" : function(c, ss){
6863                 var s = Roo.DomQuery.select;
6864                 var r = [], ri = -1;
6865                 for(var i = 0, ci; ci = c[i]; i++){
6866                     if(s(ss, ci).length > 0){
6867                         r[++ri] = ci;
6868                     }
6869                 }
6870                 return r;
6871             },
6872
6873             "next" : function(c, ss){
6874                 var is = Roo.DomQuery.is;
6875                 var r = [], ri = -1;
6876                 for(var i = 0, ci; ci = c[i]; i++){
6877                     var n = next(ci);
6878                     if(n && is(n, ss)){
6879                         r[++ri] = ci;
6880                     }
6881                 }
6882                 return r;
6883             },
6884
6885             "prev" : function(c, ss){
6886                 var is = Roo.DomQuery.is;
6887                 var r = [], ri = -1;
6888                 for(var i = 0, ci; ci = c[i]; i++){
6889                     var n = prev(ci);
6890                     if(n && is(n, ss)){
6891                         r[++ri] = ci;
6892                     }
6893                 }
6894                 return r;
6895             }
6896         }
6897     };
6898 }();
6899
6900 /**
6901  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
6902  * @param {String} path The selector/xpath query
6903  * @param {Node} root (optional) The start of the query (defaults to document).
6904  * @return {Array}
6905  * @member Roo
6906  * @method query
6907  */
6908 Roo.query = Roo.DomQuery.select;
6909 /*
6910  * Based on:
6911  * Ext JS Library 1.1.1
6912  * Copyright(c) 2006-2007, Ext JS, LLC.
6913  *
6914  * Originally Released Under LGPL - original licence link has changed is not relivant.
6915  *
6916  * Fork - LGPL
6917  * <script type="text/javascript">
6918  */
6919
6920 /**
6921  * @class Roo.util.Observable
6922  * Base class that provides a common interface for publishing events. Subclasses are expected to
6923  * to have a property "events" with all the events defined.<br>
6924  * For example:
6925  * <pre><code>
6926  Employee = function(name){
6927     this.name = name;
6928     this.addEvents({
6929         "fired" : true,
6930         "quit" : true
6931     });
6932  }
6933  Roo.extend(Employee, Roo.util.Observable);
6934 </code></pre>
6935  * @param {Object} config properties to use (incuding events / listeners)
6936  */
6937
6938 Roo.util.Observable = function(cfg){
6939     
6940     cfg = cfg|| {};
6941     this.addEvents(cfg.events || {});
6942     if (cfg.events) {
6943         delete cfg.events; // make sure
6944     }
6945      
6946     Roo.apply(this, cfg);
6947     
6948     if(this.listeners){
6949         this.on(this.listeners);
6950         delete this.listeners;
6951     }
6952 };
6953 Roo.util.Observable.prototype = {
6954     /** 
6955  * @cfg {Object} listeners  list of events and functions to call for this object, 
6956  * For example :
6957  * <pre><code>
6958     listeners :  { 
6959        'click' : function(e) {
6960            ..... 
6961         } ,
6962         .... 
6963     } 
6964   </code></pre>
6965  */
6966     
6967     
6968     /**
6969      * Fires the specified event with the passed parameters (minus the event name).
6970      * @param {String} eventName
6971      * @param {Object...} args Variable number of parameters are passed to handlers
6972      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
6973      */
6974     fireEvent : function(){
6975         var ce = this.events[arguments[0].toLowerCase()];
6976         if(typeof ce == "object"){
6977             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
6978         }else{
6979             return true;
6980         }
6981     },
6982
6983     // private
6984     filterOptRe : /^(?:scope|delay|buffer|single)$/,
6985
6986     /**
6987      * Appends an event handler to this component
6988      * @param {String}   eventName The type of event to listen for
6989      * @param {Function} handler The method the event invokes
6990      * @param {Object}   scope (optional) The scope in which to execute the handler
6991      * function. The handler function's "this" context.
6992      * @param {Object}   options (optional) An object containing handler configuration
6993      * properties. This may contain any of the following properties:<ul>
6994      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6995      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6996      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6997      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6998      * by the specified number of milliseconds. If the event fires again within that time, the original
6999      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
7000      * </ul><br>
7001      * <p>
7002      * <b>Combining Options</b><br>
7003      * Using the options argument, it is possible to combine different types of listeners:<br>
7004      * <br>
7005      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
7006                 <pre><code>
7007                 el.on('click', this.onClick, this, {
7008                         single: true,
7009                 delay: 100,
7010                 forumId: 4
7011                 });
7012                 </code></pre>
7013      * <p>
7014      * <b>Attaching multiple handlers in 1 call</b><br>
7015      * The method also allows for a single argument to be passed which is a config object containing properties
7016      * which specify multiple handlers.
7017      * <pre><code>
7018                 el.on({
7019                         'click': {
7020                         fn: this.onClick,
7021                         scope: this,
7022                         delay: 100
7023                 }, 
7024                 'mouseover': {
7025                         fn: this.onMouseOver,
7026                         scope: this
7027                 },
7028                 'mouseout': {
7029                         fn: this.onMouseOut,
7030                         scope: this
7031                 }
7032                 });
7033                 </code></pre>
7034      * <p>
7035      * Or a shorthand syntax which passes the same scope object to all handlers:
7036         <pre><code>
7037                 el.on({
7038                         'click': this.onClick,
7039                 'mouseover': this.onMouseOver,
7040                 'mouseout': this.onMouseOut,
7041                 scope: this
7042                 });
7043                 </code></pre>
7044      */
7045     addListener : function(eventName, fn, scope, o){
7046         if(typeof eventName == "object"){
7047             o = eventName;
7048             for(var e in o){
7049                 if(this.filterOptRe.test(e)){
7050                     continue;
7051                 }
7052                 if(typeof o[e] == "function"){
7053                     // shared options
7054                     this.addListener(e, o[e], o.scope,  o);
7055                 }else{
7056                     // individual options
7057                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
7058                 }
7059             }
7060             return;
7061         }
7062         o = (!o || typeof o == "boolean") ? {} : o;
7063         eventName = eventName.toLowerCase();
7064         var ce = this.events[eventName] || true;
7065         if(typeof ce == "boolean"){
7066             ce = new Roo.util.Event(this, eventName);
7067             this.events[eventName] = ce;
7068         }
7069         ce.addListener(fn, scope, o);
7070     },
7071
7072     /**
7073      * Removes a listener
7074      * @param {String}   eventName     The type of event to listen for
7075      * @param {Function} handler        The handler to remove
7076      * @param {Object}   scope  (optional) The scope (this object) for the handler
7077      */
7078     removeListener : function(eventName, fn, scope){
7079         var ce = this.events[eventName.toLowerCase()];
7080         if(typeof ce == "object"){
7081             ce.removeListener(fn, scope);
7082         }
7083     },
7084
7085     /**
7086      * Removes all listeners for this object
7087      */
7088     purgeListeners : function(){
7089         for(var evt in this.events){
7090             if(typeof this.events[evt] == "object"){
7091                  this.events[evt].clearListeners();
7092             }
7093         }
7094     },
7095
7096     relayEvents : function(o, events){
7097         var createHandler = function(ename){
7098             return function(){
7099                  
7100                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
7101             };
7102         };
7103         for(var i = 0, len = events.length; i < len; i++){
7104             var ename = events[i];
7105             if(!this.events[ename]){
7106                 this.events[ename] = true;
7107             };
7108             o.on(ename, createHandler(ename), this);
7109         }
7110     },
7111
7112     /**
7113      * Used to define events on this Observable
7114      * @param {Object} object The object with the events defined
7115      */
7116     addEvents : function(o){
7117         if(!this.events){
7118             this.events = {};
7119         }
7120         Roo.applyIf(this.events, o);
7121     },
7122
7123     /**
7124      * Checks to see if this object has any listeners for a specified event
7125      * @param {String} eventName The name of the event to check for
7126      * @return {Boolean} True if the event is being listened for, else false
7127      */
7128     hasListener : function(eventName){
7129         var e = this.events[eventName];
7130         return typeof e == "object" && e.listeners.length > 0;
7131     }
7132 };
7133 /**
7134  * Appends an event handler to this element (shorthand for addListener)
7135  * @param {String}   eventName     The type of event to listen for
7136  * @param {Function} handler        The method the event invokes
7137  * @param {Object}   scope (optional) The scope in which to execute the handler
7138  * function. The handler function's "this" context.
7139  * @param {Object}   options  (optional)
7140  * @method
7141  */
7142 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
7143 /**
7144  * Removes a listener (shorthand for removeListener)
7145  * @param {String}   eventName     The type of event to listen for
7146  * @param {Function} handler        The handler to remove
7147  * @param {Object}   scope  (optional) The scope (this object) for the handler
7148  * @method
7149  */
7150 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
7151
7152 /**
7153  * Starts capture on the specified Observable. All events will be passed
7154  * to the supplied function with the event name + standard signature of the event
7155  * <b>before</b> the event is fired. If the supplied function returns false,
7156  * the event will not fire.
7157  * @param {Observable} o The Observable to capture
7158  * @param {Function} fn The function to call
7159  * @param {Object} scope (optional) The scope (this object) for the fn
7160  * @static
7161  */
7162 Roo.util.Observable.capture = function(o, fn, scope){
7163     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
7164 };
7165
7166 /**
7167  * Removes <b>all</b> added captures from the Observable.
7168  * @param {Observable} o The Observable to release
7169  * @static
7170  */
7171 Roo.util.Observable.releaseCapture = function(o){
7172     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
7173 };
7174
7175 (function(){
7176
7177     var createBuffered = function(h, o, scope){
7178         var task = new Roo.util.DelayedTask();
7179         return function(){
7180             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
7181         };
7182     };
7183
7184     var createSingle = function(h, e, fn, scope){
7185         return function(){
7186             e.removeListener(fn, scope);
7187             return h.apply(scope, arguments);
7188         };
7189     };
7190
7191     var createDelayed = function(h, o, scope){
7192         return function(){
7193             var args = Array.prototype.slice.call(arguments, 0);
7194             setTimeout(function(){
7195                 h.apply(scope, args);
7196             }, o.delay || 10);
7197         };
7198     };
7199
7200     Roo.util.Event = function(obj, name){
7201         this.name = name;
7202         this.obj = obj;
7203         this.listeners = [];
7204     };
7205
7206     Roo.util.Event.prototype = {
7207         addListener : function(fn, scope, options){
7208             var o = options || {};
7209             scope = scope || this.obj;
7210             if(!this.isListening(fn, scope)){
7211                 var l = {fn: fn, scope: scope, options: o};
7212                 var h = fn;
7213                 if(o.delay){
7214                     h = createDelayed(h, o, scope);
7215                 }
7216                 if(o.single){
7217                     h = createSingle(h, this, fn, scope);
7218                 }
7219                 if(o.buffer){
7220                     h = createBuffered(h, o, scope);
7221                 }
7222                 l.fireFn = h;
7223                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
7224                     this.listeners.push(l);
7225                 }else{
7226                     this.listeners = this.listeners.slice(0);
7227                     this.listeners.push(l);
7228                 }
7229             }
7230         },
7231
7232         findListener : function(fn, scope){
7233             scope = scope || this.obj;
7234             var ls = this.listeners;
7235             for(var i = 0, len = ls.length; i < len; i++){
7236                 var l = ls[i];
7237                 if(l.fn == fn && l.scope == scope){
7238                     return i;
7239                 }
7240             }
7241             return -1;
7242         },
7243
7244         isListening : function(fn, scope){
7245             return this.findListener(fn, scope) != -1;
7246         },
7247
7248         removeListener : function(fn, scope){
7249             var index;
7250             if((index = this.findListener(fn, scope)) != -1){
7251                 if(!this.firing){
7252                     this.listeners.splice(index, 1);
7253                 }else{
7254                     this.listeners = this.listeners.slice(0);
7255                     this.listeners.splice(index, 1);
7256                 }
7257                 return true;
7258             }
7259             return false;
7260         },
7261
7262         clearListeners : function(){
7263             this.listeners = [];
7264         },
7265
7266         fire : function(){
7267             var ls = this.listeners, scope, len = ls.length;
7268             if(len > 0){
7269                 this.firing = true;
7270                 var args = Array.prototype.slice.call(arguments, 0);                
7271                 for(var i = 0; i < len; i++){
7272                     var l = ls[i];
7273                     if(l.fireFn.apply(l.scope||this.obj||window, args) === false){
7274                         this.firing = false;
7275                         return false;
7276                     }
7277                 }
7278                 this.firing = false;
7279             }
7280             return true;
7281         }
7282     };
7283 })();/*
7284  * RooJS Library 
7285  * Copyright(c) 2007-2017, Roo J Solutions Ltd
7286  *
7287  * Licence LGPL 
7288  *
7289  */
7290  
7291 /**
7292  * @class Roo.Document
7293  * @extends Roo.util.Observable
7294  * This is a convience class to wrap up the main document loading code.. , rather than adding Roo.onReady(......)
7295  * 
7296  * @param {Object} config the methods and properties of the 'base' class for the application.
7297  * 
7298  *  Generic Page handler - implement this to start your app..
7299  * 
7300  * eg.
7301  *  MyProject = new Roo.Document({
7302         events : {
7303             'load' : true // your events..
7304         },
7305         listeners : {
7306             'ready' : function() {
7307                 // fired on Roo.onReady()
7308             }
7309         }
7310  * 
7311  */
7312 Roo.Document = function(cfg) {
7313      
7314     this.addEvents({ 
7315         'ready' : true
7316     });
7317     Roo.util.Observable.call(this,cfg);
7318     
7319     var _this = this;
7320     
7321     Roo.onReady(function() {
7322         _this.fireEvent('ready');
7323     },null,false);
7324     
7325     
7326 }
7327
7328 Roo.extend(Roo.Document, Roo.util.Observable, {});/*
7329  * Based on:
7330  * Ext JS Library 1.1.1
7331  * Copyright(c) 2006-2007, Ext JS, LLC.
7332  *
7333  * Originally Released Under LGPL - original licence link has changed is not relivant.
7334  *
7335  * Fork - LGPL
7336  * <script type="text/javascript">
7337  */
7338
7339 /**
7340  * @class Roo.EventManager
7341  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
7342  * several useful events directly.
7343  * See {@link Roo.EventObject} for more details on normalized event objects.
7344  * @static
7345  */
7346 Roo.EventManager = function(){
7347     var docReadyEvent, docReadyProcId, docReadyState = false;
7348     var resizeEvent, resizeTask, textEvent, textSize;
7349     var E = Roo.lib.Event;
7350     var D = Roo.lib.Dom;
7351
7352     
7353     
7354
7355     var fireDocReady = function(){
7356         if(!docReadyState){
7357             docReadyState = true;
7358             Roo.isReady = true;
7359             if(docReadyProcId){
7360                 clearInterval(docReadyProcId);
7361             }
7362             if(Roo.isGecko || Roo.isOpera) {
7363                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
7364             }
7365             if(Roo.isIE){
7366                 var defer = document.getElementById("ie-deferred-loader");
7367                 if(defer){
7368                     defer.onreadystatechange = null;
7369                     defer.parentNode.removeChild(defer);
7370                 }
7371             }
7372             if(docReadyEvent){
7373                 docReadyEvent.fire();
7374                 docReadyEvent.clearListeners();
7375             }
7376         }
7377     };
7378     
7379     var initDocReady = function(){
7380         docReadyEvent = new Roo.util.Event();
7381         if(Roo.isGecko || Roo.isOpera) {
7382             document.addEventListener("DOMContentLoaded", fireDocReady, false);
7383         }else if(Roo.isIE){
7384             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
7385             var defer = document.getElementById("ie-deferred-loader");
7386             defer.onreadystatechange = function(){
7387                 if(this.readyState == "complete"){
7388                     fireDocReady();
7389                 }
7390             };
7391         }else if(Roo.isSafari){ 
7392             docReadyProcId = setInterval(function(){
7393                 var rs = document.readyState;
7394                 if(rs == "complete") {
7395                     fireDocReady();     
7396                  }
7397             }, 10);
7398         }
7399         // no matter what, make sure it fires on load
7400         E.on(window, "load", fireDocReady);
7401     };
7402
7403     var createBuffered = function(h, o){
7404         var task = new Roo.util.DelayedTask(h);
7405         return function(e){
7406             // create new event object impl so new events don't wipe out properties
7407             e = new Roo.EventObjectImpl(e);
7408             task.delay(o.buffer, h, null, [e]);
7409         };
7410     };
7411
7412     var createSingle = function(h, el, ename, fn){
7413         return function(e){
7414             Roo.EventManager.removeListener(el, ename, fn);
7415             h(e);
7416         };
7417     };
7418
7419     var createDelayed = function(h, o){
7420         return function(e){
7421             // create new event object impl so new events don't wipe out properties
7422             e = new Roo.EventObjectImpl(e);
7423             setTimeout(function(){
7424                 h(e);
7425             }, o.delay || 10);
7426         };
7427     };
7428     var transitionEndVal = false;
7429     
7430     var transitionEnd = function()
7431     {
7432         if (transitionEndVal) {
7433             return transitionEndVal;
7434         }
7435         var el = document.createElement('div');
7436
7437         var transEndEventNames = {
7438             WebkitTransition : 'webkitTransitionEnd',
7439             MozTransition    : 'transitionend',
7440             OTransition      : 'oTransitionEnd otransitionend',
7441             transition       : 'transitionend'
7442         };
7443     
7444         for (var name in transEndEventNames) {
7445             if (el.style[name] !== undefined) {
7446                 transitionEndVal = transEndEventNames[name];
7447                 return  transitionEndVal ;
7448             }
7449         }
7450     }
7451     
7452   
7453
7454     var listen = function(element, ename, opt, fn, scope)
7455     {
7456         var o = (!opt || typeof opt == "boolean") ? {} : opt;
7457         fn = fn || o.fn; scope = scope || o.scope;
7458         var el = Roo.getDom(element);
7459         
7460         
7461         if(!el){
7462             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
7463         }
7464         
7465         if (ename == 'transitionend') {
7466             ename = transitionEnd();
7467         }
7468         var h = function(e){
7469             e = Roo.EventObject.setEvent(e);
7470             var t;
7471             if(o.delegate){
7472                 t = e.getTarget(o.delegate, el);
7473                 if(!t){
7474                     return;
7475                 }
7476             }else{
7477                 t = e.target;
7478             }
7479             if(o.stopEvent === true){
7480                 e.stopEvent();
7481             }
7482             if(o.preventDefault === true){
7483                e.preventDefault();
7484             }
7485             if(o.stopPropagation === true){
7486                 e.stopPropagation();
7487             }
7488
7489             if(o.normalized === false){
7490                 e = e.browserEvent;
7491             }
7492
7493             fn.call(scope || el, e, t, o);
7494         };
7495         if(o.delay){
7496             h = createDelayed(h, o);
7497         }
7498         if(o.single){
7499             h = createSingle(h, el, ename, fn);
7500         }
7501         if(o.buffer){
7502             h = createBuffered(h, o);
7503         }
7504         
7505         fn._handlers = fn._handlers || [];
7506         
7507         
7508         fn._handlers.push([Roo.id(el), ename, h]);
7509         
7510         
7511          
7512         E.on(el, ename, h); // this adds the actuall listener to the object..
7513         
7514         
7515         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
7516             el.addEventListener("DOMMouseScroll", h, false);
7517             E.on(window, 'unload', function(){
7518                 el.removeEventListener("DOMMouseScroll", h, false);
7519             });
7520         }
7521         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
7522             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
7523         }
7524         return h;
7525     };
7526
7527     var stopListening = function(el, ename, fn){
7528         var id = Roo.id(el), hds = fn._handlers, hd = fn;
7529         if(hds){
7530             for(var i = 0, len = hds.length; i < len; i++){
7531                 var h = hds[i];
7532                 if(h[0] == id && h[1] == ename){
7533                     hd = h[2];
7534                     hds.splice(i, 1);
7535                     break;
7536                 }
7537             }
7538         }
7539         E.un(el, ename, hd);
7540         el = Roo.getDom(el);
7541         if(ename == "mousewheel" && el.addEventListener){
7542             el.removeEventListener("DOMMouseScroll", hd, false);
7543         }
7544         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
7545             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
7546         }
7547     };
7548
7549     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
7550     
7551     var pub = {
7552         
7553         
7554         /** 
7555          * Fix for doc tools
7556          * @scope Roo.EventManager
7557          */
7558         
7559         
7560         /** 
7561          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
7562          * object with a Roo.EventObject
7563          * @param {Function} fn        The method the event invokes
7564          * @param {Object}   scope    An object that becomes the scope of the handler
7565          * @param {boolean}  override If true, the obj passed in becomes
7566          *                             the execution scope of the listener
7567          * @return {Function} The wrapped function
7568          * @deprecated
7569          */
7570         wrap : function(fn, scope, override){
7571             return function(e){
7572                 Roo.EventObject.setEvent(e);
7573                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
7574             };
7575         },
7576         
7577         /**
7578      * Appends an event handler to an element (shorthand for addListener)
7579      * @param {String/HTMLElement}   element        The html element or id to assign the
7580      * @param {String}   eventName The type of event to listen for
7581      * @param {Function} handler The method the event invokes
7582      * @param {Object}   scope (optional) The scope in which to execute the handler
7583      * function. The handler function's "this" context.
7584      * @param {Object}   options (optional) An object containing handler configuration
7585      * properties. This may contain any of the following properties:<ul>
7586      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
7587      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
7588      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
7589      * <li>preventDefault {Boolean} True to prevent the default action</li>
7590      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
7591      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
7592      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
7593      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
7594      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
7595      * by the specified number of milliseconds. If the event fires again within that time, the original
7596      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
7597      * </ul><br>
7598      * <p>
7599      * <b>Combining Options</b><br>
7600      * Using the options argument, it is possible to combine different types of listeners:<br>
7601      * <br>
7602      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
7603      * Code:<pre><code>
7604 el.on('click', this.onClick, this, {
7605     single: true,
7606     delay: 100,
7607     stopEvent : true,
7608     forumId: 4
7609 });</code></pre>
7610      * <p>
7611      * <b>Attaching multiple handlers in 1 call</b><br>
7612       * The method also allows for a single argument to be passed which is a config object containing properties
7613      * which specify multiple handlers.
7614      * <p>
7615      * Code:<pre><code>
7616 el.on({
7617     'click' : {
7618         fn: this.onClick
7619         scope: this,
7620         delay: 100
7621     },
7622     'mouseover' : {
7623         fn: this.onMouseOver
7624         scope: this
7625     },
7626     'mouseout' : {
7627         fn: this.onMouseOut
7628         scope: this
7629     }
7630 });</code></pre>
7631      * <p>
7632      * Or a shorthand syntax:<br>
7633      * Code:<pre><code>
7634 el.on({
7635     'click' : this.onClick,
7636     'mouseover' : this.onMouseOver,
7637     'mouseout' : this.onMouseOut
7638     scope: this
7639 });</code></pre>
7640      */
7641         addListener : function(element, eventName, fn, scope, options){
7642             if(typeof eventName == "object"){
7643                 var o = eventName;
7644                 for(var e in o){
7645                     if(propRe.test(e)){
7646                         continue;
7647                     }
7648                     if(typeof o[e] == "function"){
7649                         // shared options
7650                         listen(element, e, o, o[e], o.scope);
7651                     }else{
7652                         // individual options
7653                         listen(element, e, o[e]);
7654                     }
7655                 }
7656                 return;
7657             }
7658             return listen(element, eventName, options, fn, scope);
7659         },
7660         
7661         /**
7662          * Removes an event handler
7663          *
7664          * @param {String/HTMLElement}   element        The id or html element to remove the 
7665          *                             event from
7666          * @param {String}   eventName     The type of event
7667          * @param {Function} fn
7668          * @return {Boolean} True if a listener was actually removed
7669          */
7670         removeListener : function(element, eventName, fn){
7671             return stopListening(element, eventName, fn);
7672         },
7673         
7674         /**
7675          * Fires when the document is ready (before onload and before images are loaded). Can be 
7676          * accessed shorthanded Roo.onReady().
7677          * @param {Function} fn        The method the event invokes
7678          * @param {Object}   scope    An  object that becomes the scope of the handler
7679          * @param {boolean}  options
7680          */
7681         onDocumentReady : function(fn, scope, options){
7682             if(docReadyState){ // if it already fired
7683                 docReadyEvent.addListener(fn, scope, options);
7684                 docReadyEvent.fire();
7685                 docReadyEvent.clearListeners();
7686                 return;
7687             }
7688             if(!docReadyEvent){
7689                 initDocReady();
7690             }
7691             docReadyEvent.addListener(fn, scope, options);
7692         },
7693         
7694         /**
7695          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
7696          * @param {Function} fn        The method the event invokes
7697          * @param {Object}   scope    An object that becomes the scope of the handler
7698          * @param {boolean}  options
7699          */
7700         onWindowResize : function(fn, scope, options)
7701         {
7702             if(!resizeEvent){
7703                 resizeEvent = new Roo.util.Event();
7704                 resizeTask = new Roo.util.DelayedTask(function(){
7705                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
7706                 });
7707                 E.on(window, "resize", function()
7708                 {
7709                     if (Roo.isIE) {
7710                         resizeTask.delay(50);
7711                     } else {
7712                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
7713                     }
7714                 });
7715             }
7716             resizeEvent.addListener(fn, scope, options);
7717         },
7718
7719         /**
7720          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
7721          * @param {Function} fn        The method the event invokes
7722          * @param {Object}   scope    An object that becomes the scope of the handler
7723          * @param {boolean}  options
7724          */
7725         onTextResize : function(fn, scope, options){
7726             if(!textEvent){
7727                 textEvent = new Roo.util.Event();
7728                 var textEl = new Roo.Element(document.createElement('div'));
7729                 textEl.dom.className = 'x-text-resize';
7730                 textEl.dom.innerHTML = 'X';
7731                 textEl.appendTo(document.body);
7732                 textSize = textEl.dom.offsetHeight;
7733                 setInterval(function(){
7734                     if(textEl.dom.offsetHeight != textSize){
7735                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
7736                     }
7737                 }, this.textResizeInterval);
7738             }
7739             textEvent.addListener(fn, scope, options);
7740         },
7741
7742         /**
7743          * Removes the passed window resize listener.
7744          * @param {Function} fn        The method the event invokes
7745          * @param {Object}   scope    The scope of handler
7746          */
7747         removeResizeListener : function(fn, scope){
7748             if(resizeEvent){
7749                 resizeEvent.removeListener(fn, scope);
7750             }
7751         },
7752
7753         // private
7754         fireResize : function(){
7755             if(resizeEvent){
7756                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
7757             }   
7758         },
7759         /**
7760          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
7761          */
7762         ieDeferSrc : false,
7763         /**
7764          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
7765          */
7766         textResizeInterval : 50
7767     };
7768     
7769     /**
7770      * Fix for doc tools
7771      * @scopeAlias pub=Roo.EventManager
7772      */
7773     
7774      /**
7775      * Appends an event handler to an element (shorthand for addListener)
7776      * @param {String/HTMLElement}   element        The html element or id to assign the
7777      * @param {String}   eventName The type of event to listen for
7778      * @param {Function} handler The method the event invokes
7779      * @param {Object}   scope (optional) The scope in which to execute the handler
7780      * function. The handler function's "this" context.
7781      * @param {Object}   options (optional) An object containing handler configuration
7782      * properties. This may contain any of the following properties:<ul>
7783      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
7784      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
7785      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
7786      * <li>preventDefault {Boolean} True to prevent the default action</li>
7787      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
7788      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
7789      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
7790      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
7791      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
7792      * by the specified number of milliseconds. If the event fires again within that time, the original
7793      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
7794      * </ul><br>
7795      * <p>
7796      * <b>Combining Options</b><br>
7797      * Using the options argument, it is possible to combine different types of listeners:<br>
7798      * <br>
7799      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
7800      * Code:<pre><code>
7801 el.on('click', this.onClick, this, {
7802     single: true,
7803     delay: 100,
7804     stopEvent : true,
7805     forumId: 4
7806 });</code></pre>
7807      * <p>
7808      * <b>Attaching multiple handlers in 1 call</b><br>
7809       * The method also allows for a single argument to be passed which is a config object containing properties
7810      * which specify multiple handlers.
7811      * <p>
7812      * Code:<pre><code>
7813 el.on({
7814     'click' : {
7815         fn: this.onClick
7816         scope: this,
7817         delay: 100
7818     },
7819     'mouseover' : {
7820         fn: this.onMouseOver
7821         scope: this
7822     },
7823     'mouseout' : {
7824         fn: this.onMouseOut
7825         scope: this
7826     }
7827 });</code></pre>
7828      * <p>
7829      * Or a shorthand syntax:<br>
7830      * Code:<pre><code>
7831 el.on({
7832     'click' : this.onClick,
7833     'mouseover' : this.onMouseOver,
7834     'mouseout' : this.onMouseOut
7835     scope: this
7836 });</code></pre>
7837      */
7838     pub.on = pub.addListener;
7839     pub.un = pub.removeListener;
7840
7841     pub.stoppedMouseDownEvent = new Roo.util.Event();
7842     return pub;
7843 }();
7844 /**
7845   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
7846   * @param {Function} fn        The method the event invokes
7847   * @param {Object}   scope    An  object that becomes the scope of the handler
7848   * @param {boolean}  override If true, the obj passed in becomes
7849   *                             the execution scope of the listener
7850   * @member Roo
7851   * @method onReady
7852  */
7853 Roo.onReady = Roo.EventManager.onDocumentReady;
7854
7855 Roo.onReady(function(){
7856     var bd = Roo.get(document.body);
7857     if(!bd){ return; }
7858
7859     var cls = [
7860             Roo.isIE ? "roo-ie"
7861             : Roo.isIE11 ? "roo-ie11"
7862             : Roo.isEdge ? "roo-edge"
7863             : Roo.isGecko ? "roo-gecko"
7864             : Roo.isOpera ? "roo-opera"
7865             : Roo.isSafari ? "roo-safari" : ""];
7866
7867     if(Roo.isMac){
7868         cls.push("roo-mac");
7869     }
7870     if(Roo.isLinux){
7871         cls.push("roo-linux");
7872     }
7873     if(Roo.isIOS){
7874         cls.push("roo-ios");
7875     }
7876     if(Roo.isTouch){
7877         cls.push("roo-touch");
7878     }
7879     if(Roo.isBorderBox){
7880         cls.push('roo-border-box');
7881     }
7882     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
7883         var p = bd.dom.parentNode;
7884         if(p){
7885             p.className += ' roo-strict';
7886         }
7887     }
7888     bd.addClass(cls.join(' '));
7889 });
7890
7891 /**
7892  * @class Roo.EventObject
7893  * EventObject exposes the Yahoo! UI Event functionality directly on the object
7894  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
7895  * Example:
7896  * <pre><code>
7897  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
7898     e.preventDefault();
7899     var target = e.getTarget();
7900     ...
7901  }
7902  var myDiv = Roo.get("myDiv");
7903  myDiv.on("click", handleClick);
7904  //or
7905  Roo.EventManager.on("myDiv", 'click', handleClick);
7906  Roo.EventManager.addListener("myDiv", 'click', handleClick);
7907  </code></pre>
7908  * @static
7909  */
7910 Roo.EventObject = function(){
7911     
7912     var E = Roo.lib.Event;
7913     
7914     // safari keypress events for special keys return bad keycodes
7915     var safariKeys = {
7916         63234 : 37, // left
7917         63235 : 39, // right
7918         63232 : 38, // up
7919         63233 : 40, // down
7920         63276 : 33, // page up
7921         63277 : 34, // page down
7922         63272 : 46, // delete
7923         63273 : 36, // home
7924         63275 : 35  // end
7925     };
7926
7927     // normalize button clicks
7928     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
7929                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
7930
7931     Roo.EventObjectImpl = function(e){
7932         if(e){
7933             this.setEvent(e.browserEvent || e);
7934         }
7935     };
7936     Roo.EventObjectImpl.prototype = {
7937         /**
7938          * Used to fix doc tools.
7939          * @scope Roo.EventObject.prototype
7940          */
7941             
7942
7943         
7944         
7945         /** The normal browser event */
7946         browserEvent : null,
7947         /** The button pressed in a mouse event */
7948         button : -1,
7949         /** True if the shift key was down during the event */
7950         shiftKey : false,
7951         /** True if the control key was down during the event */
7952         ctrlKey : false,
7953         /** True if the alt key was down during the event */
7954         altKey : false,
7955
7956         /** Key constant 
7957         * @type Number */
7958         BACKSPACE : 8,
7959         /** Key constant 
7960         * @type Number */
7961         TAB : 9,
7962         /** Key constant 
7963         * @type Number */
7964         RETURN : 13,
7965         /** Key constant 
7966         * @type Number */
7967         ENTER : 13,
7968         /** Key constant 
7969         * @type Number */
7970         SHIFT : 16,
7971         /** Key constant 
7972         * @type Number */
7973         CONTROL : 17,
7974         /** Key constant 
7975         * @type Number */
7976         ESC : 27,
7977         /** Key constant 
7978         * @type Number */
7979         SPACE : 32,
7980         /** Key constant 
7981         * @type Number */
7982         PAGEUP : 33,
7983         /** Key constant 
7984         * @type Number */
7985         PAGEDOWN : 34,
7986         /** Key constant 
7987         * @type Number */
7988         END : 35,
7989         /** Key constant 
7990         * @type Number */
7991         HOME : 36,
7992         /** Key constant 
7993         * @type Number */
7994         LEFT : 37,
7995         /** Key constant 
7996         * @type Number */
7997         UP : 38,
7998         /** Key constant 
7999         * @type Number */
8000         RIGHT : 39,
8001         /** Key constant 
8002         * @type Number */
8003         DOWN : 40,
8004         /** Key constant 
8005         * @type Number */
8006         DELETE : 46,
8007         /** Key constant 
8008         * @type Number */
8009         F5 : 116,
8010
8011            /** @private */
8012         setEvent : function(e){
8013             if(e == this || (e && e.browserEvent)){ // already wrapped
8014                 return e;
8015             }
8016             this.browserEvent = e;
8017             if(e){
8018                 // normalize buttons
8019                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
8020                 if(e.type == 'click' && this.button == -1){
8021                     this.button = 0;
8022                 }
8023                 this.type = e.type;
8024                 this.shiftKey = e.shiftKey;
8025                 // mac metaKey behaves like ctrlKey
8026                 this.ctrlKey = e.ctrlKey || e.metaKey;
8027                 this.altKey = e.altKey;
8028                 // in getKey these will be normalized for the mac
8029                 this.keyCode = e.keyCode;
8030                 // keyup warnings on firefox.
8031                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
8032                 // cache the target for the delayed and or buffered events
8033                 this.target = E.getTarget(e);
8034                 // same for XY
8035                 this.xy = E.getXY(e);
8036             }else{
8037                 this.button = -1;
8038                 this.shiftKey = false;
8039                 this.ctrlKey = false;
8040                 this.altKey = false;
8041                 this.keyCode = 0;
8042                 this.charCode =0;
8043                 this.target = null;
8044                 this.xy = [0, 0];
8045             }
8046             return this;
8047         },
8048
8049         /**
8050          * Stop the event (preventDefault and stopPropagation)
8051          */
8052         stopEvent : function(){
8053             if(this.browserEvent){
8054                 if(this.browserEvent.type == 'mousedown'){
8055                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
8056                 }
8057                 E.stopEvent(this.browserEvent);
8058             }
8059         },
8060
8061         /**
8062          * Prevents the browsers default handling of the event.
8063          */
8064         preventDefault : function(){
8065             if(this.browserEvent){
8066                 E.preventDefault(this.browserEvent);
8067             }
8068         },
8069
8070         /** @private */
8071         isNavKeyPress : function(){
8072             var k = this.keyCode;
8073             k = Roo.isSafari ? (safariKeys[k] || k) : k;
8074             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
8075         },
8076
8077         isSpecialKey : function(){
8078             var k = this.keyCode;
8079             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
8080             (k == 16) || (k == 17) ||
8081             (k >= 18 && k <= 20) ||
8082             (k >= 33 && k <= 35) ||
8083             (k >= 36 && k <= 39) ||
8084             (k >= 44 && k <= 45);
8085         },
8086         /**
8087          * Cancels bubbling of the event.
8088          */
8089         stopPropagation : function(){
8090             if(this.browserEvent){
8091                 if(this.type == 'mousedown'){
8092                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
8093                 }
8094                 E.stopPropagation(this.browserEvent);
8095             }
8096         },
8097
8098         /**
8099          * Gets the key code for the event.
8100          * @return {Number}
8101          */
8102         getCharCode : function(){
8103             return this.charCode || this.keyCode;
8104         },
8105
8106         /**
8107          * Returns a normalized keyCode for the event.
8108          * @return {Number} The key code
8109          */
8110         getKey : function(){
8111             var k = this.keyCode || this.charCode;
8112             return Roo.isSafari ? (safariKeys[k] || k) : k;
8113         },
8114
8115         /**
8116          * Gets the x coordinate of the event.
8117          * @return {Number}
8118          */
8119         getPageX : function(){
8120             return this.xy[0];
8121         },
8122
8123         /**
8124          * Gets the y coordinate of the event.
8125          * @return {Number}
8126          */
8127         getPageY : function(){
8128             return this.xy[1];
8129         },
8130
8131         /**
8132          * Gets the time of the event.
8133          * @return {Number}
8134          */
8135         getTime : function(){
8136             if(this.browserEvent){
8137                 return E.getTime(this.browserEvent);
8138             }
8139             return null;
8140         },
8141
8142         /**
8143          * Gets the page coordinates of the event.
8144          * @return {Array} The xy values like [x, y]
8145          */
8146         getXY : function(){
8147             return this.xy;
8148         },
8149
8150         /**
8151          * Gets the target for the event.
8152          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
8153          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8154                 search as a number or element (defaults to 10 || document.body)
8155          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
8156          * @return {HTMLelement}
8157          */
8158         getTarget : function(selector, maxDepth, returnEl){
8159             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
8160         },
8161         /**
8162          * Gets the related target.
8163          * @return {HTMLElement}
8164          */
8165         getRelatedTarget : function(){
8166             if(this.browserEvent){
8167                 return E.getRelatedTarget(this.browserEvent);
8168             }
8169             return null;
8170         },
8171
8172         /**
8173          * Normalizes mouse wheel delta across browsers
8174          * @return {Number} The delta
8175          */
8176         getWheelDelta : function(){
8177             var e = this.browserEvent;
8178             var delta = 0;
8179             if(e.wheelDelta){ /* IE/Opera. */
8180                 delta = e.wheelDelta/120;
8181             }else if(e.detail){ /* Mozilla case. */
8182                 delta = -e.detail/3;
8183             }
8184             return delta;
8185         },
8186
8187         /**
8188          * Returns true if the control, meta, shift or alt key was pressed during this event.
8189          * @return {Boolean}
8190          */
8191         hasModifier : function(){
8192             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
8193         },
8194
8195         /**
8196          * Returns true if the target of this event equals el or is a child of el
8197          * @param {String/HTMLElement/Element} el
8198          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
8199          * @return {Boolean}
8200          */
8201         within : function(el, related){
8202             var t = this[related ? "getRelatedTarget" : "getTarget"]();
8203             return t && Roo.fly(el).contains(t);
8204         },
8205
8206         getPoint : function(){
8207             return new Roo.lib.Point(this.xy[0], this.xy[1]);
8208         }
8209     };
8210
8211     return new Roo.EventObjectImpl();
8212 }();
8213             
8214     /*
8215  * Based on:
8216  * Ext JS Library 1.1.1
8217  * Copyright(c) 2006-2007, Ext JS, LLC.
8218  *
8219  * Originally Released Under LGPL - original licence link has changed is not relivant.
8220  *
8221  * Fork - LGPL
8222  * <script type="text/javascript">
8223  */
8224
8225  
8226 // was in Composite Element!??!?!
8227  
8228 (function(){
8229     var D = Roo.lib.Dom;
8230     var E = Roo.lib.Event;
8231     var A = Roo.lib.Anim;
8232
8233     // local style camelizing for speed
8234     var propCache = {};
8235     var camelRe = /(-[a-z])/gi;
8236     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
8237     var view = document.defaultView;
8238
8239 /**
8240  * @class Roo.Element
8241  * Represents an Element in the DOM.<br><br>
8242  * Usage:<br>
8243 <pre><code>
8244 var el = Roo.get("my-div");
8245
8246 // or with getEl
8247 var el = getEl("my-div");
8248
8249 // or with a DOM element
8250 var el = Roo.get(myDivElement);
8251 </code></pre>
8252  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
8253  * each call instead of constructing a new one.<br><br>
8254  * <b>Animations</b><br />
8255  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
8256  * should either be a boolean (true) or an object literal with animation options. The animation options are:
8257 <pre>
8258 Option    Default   Description
8259 --------- --------  ---------------------------------------------
8260 duration  .35       The duration of the animation in seconds
8261 easing    easeOut   The YUI easing method
8262 callback  none      A function to execute when the anim completes
8263 scope     this      The scope (this) of the callback function
8264 </pre>
8265 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
8266 * manipulate the animation. Here's an example:
8267 <pre><code>
8268 var el = Roo.get("my-div");
8269
8270 // no animation
8271 el.setWidth(100);
8272
8273 // default animation
8274 el.setWidth(100, true);
8275
8276 // animation with some options set
8277 el.setWidth(100, {
8278     duration: 1,
8279     callback: this.foo,
8280     scope: this
8281 });
8282
8283 // using the "anim" property to get the Anim object
8284 var opt = {
8285     duration: 1,
8286     callback: this.foo,
8287     scope: this
8288 };
8289 el.setWidth(100, opt);
8290 ...
8291 if(opt.anim.isAnimated()){
8292     opt.anim.stop();
8293 }
8294 </code></pre>
8295 * <b> Composite (Collections of) Elements</b><br />
8296  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
8297  * @constructor Create a new Element directly.
8298  * @param {String/HTMLElement} element
8299  * @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).
8300  */
8301     Roo.Element = function(element, forceNew)
8302     {
8303         var dom = typeof element == "string" ?
8304                 document.getElementById(element) : element;
8305         
8306         this.listeners = {};
8307         
8308         if(!dom){ // invalid id/element
8309             return null;
8310         }
8311         var id = dom.id;
8312         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
8313             return Roo.Element.cache[id];
8314         }
8315
8316         /**
8317          * The DOM element
8318          * @type HTMLElement
8319          */
8320         this.dom = dom;
8321
8322         /**
8323          * The DOM element ID
8324          * @type String
8325          */
8326         this.id = id || Roo.id(dom);
8327         
8328         return this; // assumed for cctor?
8329     };
8330
8331     var El = Roo.Element;
8332
8333     El.prototype = {
8334         /**
8335          * The element's default display mode  (defaults to "") 
8336          * @type String
8337          */
8338         originalDisplay : "",
8339
8340         
8341         // note this is overridden in BS version..
8342         visibilityMode : 1, 
8343         /**
8344          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
8345          * @type String
8346          */
8347         defaultUnit : "px",
8348         
8349         /**
8350          * Sets the element's visibility mode. When setVisible() is called it
8351          * will use this to determine whether to set the visibility or the display property.
8352          * @param visMode Element.VISIBILITY or Element.DISPLAY
8353          * @return {Roo.Element} this
8354          */
8355         setVisibilityMode : function(visMode){
8356             this.visibilityMode = visMode;
8357             return this;
8358         },
8359         /**
8360          * Convenience method for setVisibilityMode(Element.DISPLAY)
8361          * @param {String} display (optional) What to set display to when visible
8362          * @return {Roo.Element} this
8363          */
8364         enableDisplayMode : function(display){
8365             this.setVisibilityMode(El.DISPLAY);
8366             if(typeof display != "undefined") { this.originalDisplay = display; }
8367             return this;
8368         },
8369
8370         /**
8371          * 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)
8372          * @param {String} selector The simple selector to test
8373          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8374                 search as a number or element (defaults to 10 || document.body)
8375          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
8376          * @return {HTMLElement} The matching DOM node (or null if no match was found)
8377          */
8378         findParent : function(simpleSelector, maxDepth, returnEl){
8379             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
8380             maxDepth = maxDepth || 50;
8381             if(typeof maxDepth != "number"){
8382                 stopEl = Roo.getDom(maxDepth);
8383                 maxDepth = 10;
8384             }
8385             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
8386                 if(dq.is(p, simpleSelector)){
8387                     return returnEl ? Roo.get(p) : p;
8388                 }
8389                 depth++;
8390                 p = p.parentNode;
8391             }
8392             return null;
8393         },
8394
8395
8396         /**
8397          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
8398          * @param {String} selector The simple selector to test
8399          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8400                 search as a number or element (defaults to 10 || document.body)
8401          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
8402          * @return {HTMLElement} The matching DOM node (or null if no match was found)
8403          */
8404         findParentNode : function(simpleSelector, maxDepth, returnEl){
8405             var p = Roo.fly(this.dom.parentNode, '_internal');
8406             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
8407         },
8408         
8409         /**
8410          * Looks at  the scrollable parent element
8411          */
8412         findScrollableParent : function()
8413         {
8414             var overflowRegex = /(auto|scroll)/;
8415             
8416             if(this.getStyle('position') === 'fixed'){
8417                 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
8418             }
8419             
8420             var excludeStaticParent = this.getStyle('position') === "absolute";
8421             
8422             for (var parent = this; (parent = Roo.get(parent.dom.parentNode));){
8423                 
8424                 if (excludeStaticParent && parent.getStyle('position') === "static") {
8425                     continue;
8426                 }
8427                 
8428                 if (overflowRegex.test(parent.getStyle('overflow') + parent.getStyle('overflow-x') + parent.getStyle('overflow-y'))){
8429                     return parent;
8430                 }
8431                 
8432                 if(parent.dom.nodeName.toLowerCase() == 'body'){
8433                     return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
8434                 }
8435             }
8436             
8437             return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
8438         },
8439
8440         /**
8441          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
8442          * This is a shortcut for findParentNode() that always returns an Roo.Element.
8443          * @param {String} selector The simple selector to test
8444          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8445                 search as a number or element (defaults to 10 || document.body)
8446          * @return {Roo.Element} The matching DOM node (or null if no match was found)
8447          */
8448         up : function(simpleSelector, maxDepth){
8449             return this.findParentNode(simpleSelector, maxDepth, true);
8450         },
8451
8452
8453
8454         /**
8455          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
8456          * @param {String} selector The simple selector to test
8457          * @return {Boolean} True if this element matches the selector, else false
8458          */
8459         is : function(simpleSelector){
8460             return Roo.DomQuery.is(this.dom, simpleSelector);
8461         },
8462
8463         /**
8464          * Perform animation on this element.
8465          * @param {Object} args The YUI animation control args
8466          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
8467          * @param {Function} onComplete (optional) Function to call when animation completes
8468          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
8469          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
8470          * @return {Roo.Element} this
8471          */
8472         animate : function(args, duration, onComplete, easing, animType){
8473             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
8474             return this;
8475         },
8476
8477         /*
8478          * @private Internal animation call
8479          */
8480         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
8481             animType = animType || 'run';
8482             opt = opt || {};
8483             var anim = Roo.lib.Anim[animType](
8484                 this.dom, args,
8485                 (opt.duration || defaultDur) || .35,
8486                 (opt.easing || defaultEase) || 'easeOut',
8487                 function(){
8488                     Roo.callback(cb, this);
8489                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
8490                 },
8491                 this
8492             );
8493             opt.anim = anim;
8494             return anim;
8495         },
8496
8497         // private legacy anim prep
8498         preanim : function(a, i){
8499             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
8500         },
8501
8502         /**
8503          * Removes worthless text nodes
8504          * @param {Boolean} forceReclean (optional) By default the element
8505          * keeps track if it has been cleaned already so
8506          * you can call this over and over. However, if you update the element and
8507          * need to force a reclean, you can pass true.
8508          */
8509         clean : function(forceReclean){
8510             if(this.isCleaned && forceReclean !== true){
8511                 return this;
8512             }
8513             var ns = /\S/;
8514             var d = this.dom, n = d.firstChild, ni = -1;
8515             while(n){
8516                 var nx = n.nextSibling;
8517                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
8518                     d.removeChild(n);
8519                 }else{
8520                     n.nodeIndex = ++ni;
8521                 }
8522                 n = nx;
8523             }
8524             this.isCleaned = true;
8525             return this;
8526         },
8527
8528         // private
8529         calcOffsetsTo : function(el){
8530             el = Roo.get(el);
8531             var d = el.dom;
8532             var restorePos = false;
8533             if(el.getStyle('position') == 'static'){
8534                 el.position('relative');
8535                 restorePos = true;
8536             }
8537             var x = 0, y =0;
8538             var op = this.dom;
8539             while(op && op != d && op.tagName != 'HTML'){
8540                 x+= op.offsetLeft;
8541                 y+= op.offsetTop;
8542                 op = op.offsetParent;
8543             }
8544             if(restorePos){
8545                 el.position('static');
8546             }
8547             return [x, y];
8548         },
8549
8550         /**
8551          * Scrolls this element into view within the passed container.
8552          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
8553          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
8554          * @return {Roo.Element} this
8555          */
8556         scrollIntoView : function(container, hscroll){
8557             var c = Roo.getDom(container) || document.body;
8558             var el = this.dom;
8559
8560             var o = this.calcOffsetsTo(c),
8561                 l = o[0],
8562                 t = o[1],
8563                 b = t+el.offsetHeight,
8564                 r = l+el.offsetWidth;
8565
8566             var ch = c.clientHeight;
8567             var ct = parseInt(c.scrollTop, 10);
8568             var cl = parseInt(c.scrollLeft, 10);
8569             var cb = ct + ch;
8570             var cr = cl + c.clientWidth;
8571
8572             if(t < ct){
8573                 c.scrollTop = t;
8574             }else if(b > cb){
8575                 c.scrollTop = b-ch;
8576             }
8577
8578             if(hscroll !== false){
8579                 if(l < cl){
8580                     c.scrollLeft = l;
8581                 }else if(r > cr){
8582                     c.scrollLeft = r-c.clientWidth;
8583                 }
8584             }
8585             return this;
8586         },
8587
8588         // private
8589         scrollChildIntoView : function(child, hscroll){
8590             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
8591         },
8592
8593         /**
8594          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
8595          * the new height may not be available immediately.
8596          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
8597          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
8598          * @param {Function} onComplete (optional) Function to call when animation completes
8599          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
8600          * @return {Roo.Element} this
8601          */
8602         autoHeight : function(animate, duration, onComplete, easing){
8603             var oldHeight = this.getHeight();
8604             this.clip();
8605             this.setHeight(1); // force clipping
8606             setTimeout(function(){
8607                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
8608                 if(!animate){
8609                     this.setHeight(height);
8610                     this.unclip();
8611                     if(typeof onComplete == "function"){
8612                         onComplete();
8613                     }
8614                 }else{
8615                     this.setHeight(oldHeight); // restore original height
8616                     this.setHeight(height, animate, duration, function(){
8617                         this.unclip();
8618                         if(typeof onComplete == "function") { onComplete(); }
8619                     }.createDelegate(this), easing);
8620                 }
8621             }.createDelegate(this), 0);
8622             return this;
8623         },
8624
8625         /**
8626          * Returns true if this element is an ancestor of the passed element
8627          * @param {HTMLElement/String} el The element to check
8628          * @return {Boolean} True if this element is an ancestor of el, else false
8629          */
8630         contains : function(el){
8631             if(!el){return false;}
8632             return D.isAncestor(this.dom, el.dom ? el.dom : el);
8633         },
8634
8635         /**
8636          * Checks whether the element is currently visible using both visibility and display properties.
8637          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
8638          * @return {Boolean} True if the element is currently visible, else false
8639          */
8640         isVisible : function(deep) {
8641             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
8642             if(deep !== true || !vis){
8643                 return vis;
8644             }
8645             var p = this.dom.parentNode;
8646             while(p && p.tagName.toLowerCase() != "body"){
8647                 if(!Roo.fly(p, '_isVisible').isVisible()){
8648                     return false;
8649                 }
8650                 p = p.parentNode;
8651             }
8652             return true;
8653         },
8654
8655         /**
8656          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
8657          * @param {String} selector The CSS selector
8658          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
8659          * @return {CompositeElement/CompositeElementLite} The composite element
8660          */
8661         select : function(selector, unique){
8662             return El.select(selector, unique, this.dom);
8663         },
8664
8665         /**
8666          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
8667          * @param {String} selector The CSS selector
8668          * @return {Array} An array of the matched nodes
8669          */
8670         query : function(selector, unique){
8671             return Roo.DomQuery.select(selector, this.dom);
8672         },
8673
8674         /**
8675          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
8676          * @param {String} selector The CSS selector
8677          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
8678          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
8679          */
8680         child : function(selector, returnDom){
8681             var n = Roo.DomQuery.selectNode(selector, this.dom);
8682             return returnDom ? n : Roo.get(n);
8683         },
8684
8685         /**
8686          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
8687          * @param {String} selector The CSS selector
8688          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
8689          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
8690          */
8691         down : function(selector, returnDom){
8692             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
8693             return returnDom ? n : Roo.get(n);
8694         },
8695
8696         /**
8697          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
8698          * @param {String} group The group the DD object is member of
8699          * @param {Object} config The DD config object
8700          * @param {Object} overrides An object containing methods to override/implement on the DD object
8701          * @return {Roo.dd.DD} The DD object
8702          */
8703         initDD : function(group, config, overrides){
8704             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
8705             return Roo.apply(dd, overrides);
8706         },
8707
8708         /**
8709          * Initializes a {@link Roo.dd.DDProxy} object for this element.
8710          * @param {String} group The group the DDProxy object is member of
8711          * @param {Object} config The DDProxy config object
8712          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
8713          * @return {Roo.dd.DDProxy} The DDProxy object
8714          */
8715         initDDProxy : function(group, config, overrides){
8716             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
8717             return Roo.apply(dd, overrides);
8718         },
8719
8720         /**
8721          * Initializes a {@link Roo.dd.DDTarget} object for this element.
8722          * @param {String} group The group the DDTarget object is member of
8723          * @param {Object} config The DDTarget config object
8724          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
8725          * @return {Roo.dd.DDTarget} The DDTarget object
8726          */
8727         initDDTarget : function(group, config, overrides){
8728             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
8729             return Roo.apply(dd, overrides);
8730         },
8731
8732         /**
8733          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
8734          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
8735          * @param {Boolean} visible Whether the element is visible
8736          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8737          * @return {Roo.Element} this
8738          */
8739          setVisible : function(visible, animate){
8740             if(!animate || !A){
8741                 if(this.visibilityMode == El.DISPLAY){
8742                     this.setDisplayed(visible);
8743                 }else{
8744                     this.fixDisplay();
8745                     this.dom.style.visibility = visible ? "visible" : "hidden";
8746                 }
8747             }else{
8748                 // closure for composites
8749                 var dom = this.dom;
8750                 var visMode = this.visibilityMode;
8751                 if(visible){
8752                     this.setOpacity(.01);
8753                     this.setVisible(true);
8754                 }
8755                 this.anim({opacity: { to: (visible?1:0) }},
8756                       this.preanim(arguments, 1),
8757                       null, .35, 'easeIn', function(){
8758                          if(!visible){
8759                              if(visMode == El.DISPLAY){
8760                                  dom.style.display = "none";
8761                              }else{
8762                                  dom.style.visibility = "hidden";
8763                              }
8764                              Roo.get(dom).setOpacity(1);
8765                          }
8766                      });
8767             }
8768             return this;
8769         },
8770
8771         /**
8772          * Returns true if display is not "none"
8773          * @return {Boolean}
8774          */
8775         isDisplayed : function() {
8776             return this.getStyle("display") != "none";
8777         },
8778
8779         /**
8780          * Toggles the element's visibility or display, depending on visibility mode.
8781          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8782          * @return {Roo.Element} this
8783          */
8784         toggle : function(animate){
8785             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
8786             return this;
8787         },
8788
8789         /**
8790          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
8791          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
8792          * @return {Roo.Element} this
8793          */
8794         setDisplayed : function(value) {
8795             if(typeof value == "boolean"){
8796                value = value ? this.originalDisplay : "none";
8797             }
8798             this.setStyle("display", value);
8799             return this;
8800         },
8801
8802         /**
8803          * Tries to focus the element. Any exceptions are caught and ignored.
8804          * @return {Roo.Element} this
8805          */
8806         focus : function() {
8807             try{
8808                 this.dom.focus();
8809             }catch(e){}
8810             return this;
8811         },
8812
8813         /**
8814          * Tries to blur the element. Any exceptions are caught and ignored.
8815          * @return {Roo.Element} this
8816          */
8817         blur : function() {
8818             try{
8819                 this.dom.blur();
8820             }catch(e){}
8821             return this;
8822         },
8823
8824         /**
8825          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
8826          * @param {String/Array} className The CSS class to add, or an array of classes
8827          * @return {Roo.Element} this
8828          */
8829         addClass : function(className){
8830             if(className instanceof Array){
8831                 for(var i = 0, len = className.length; i < len; i++) {
8832                     this.addClass(className[i]);
8833                 }
8834             }else{
8835                 if(className && !this.hasClass(className)){
8836                     if (this.dom instanceof SVGElement) {
8837                         this.dom.className.baseVal =this.dom.className.baseVal  + " " + className;
8838                     } else {
8839                         this.dom.className = this.dom.className + " " + className;
8840                     }
8841                 }
8842             }
8843             return this;
8844         },
8845
8846         /**
8847          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
8848          * @param {String/Array} className The CSS class to add, or an array of classes
8849          * @return {Roo.Element} this
8850          */
8851         radioClass : function(className){
8852             var siblings = this.dom.parentNode.childNodes;
8853             for(var i = 0; i < siblings.length; i++) {
8854                 var s = siblings[i];
8855                 if(s.nodeType == 1){
8856                     Roo.get(s).removeClass(className);
8857                 }
8858             }
8859             this.addClass(className);
8860             return this;
8861         },
8862
8863         /**
8864          * Removes one or more CSS classes from the element.
8865          * @param {String/Array} className The CSS class to remove, or an array of classes
8866          * @return {Roo.Element} this
8867          */
8868         removeClass : function(className){
8869             
8870             var cn = this.dom instanceof SVGElement ? this.dom.className.baseVal : this.dom.className;
8871             if(!className || !cn){
8872                 return this;
8873             }
8874             if(className instanceof Array){
8875                 for(var i = 0, len = className.length; i < len; i++) {
8876                     this.removeClass(className[i]);
8877                 }
8878             }else{
8879                 if(this.hasClass(className)){
8880                     var re = this.classReCache[className];
8881                     if (!re) {
8882                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
8883                        this.classReCache[className] = re;
8884                     }
8885                     if (this.dom instanceof SVGElement) {
8886                         this.dom.className.baseVal = cn.replace(re, " ");
8887                     } else {
8888                         this.dom.className = cn.replace(re, " ");
8889                     }
8890                 }
8891             }
8892             return this;
8893         },
8894
8895         // private
8896         classReCache: {},
8897
8898         /**
8899          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
8900          * @param {String} className The CSS class to toggle
8901          * @return {Roo.Element} this
8902          */
8903         toggleClass : function(className){
8904             if(this.hasClass(className)){
8905                 this.removeClass(className);
8906             }else{
8907                 this.addClass(className);
8908             }
8909             return this;
8910         },
8911
8912         /**
8913          * Checks if the specified CSS class exists on this element's DOM node.
8914          * @param {String} className The CSS class to check for
8915          * @return {Boolean} True if the class exists, else false
8916          */
8917         hasClass : function(className){
8918             if (this.dom instanceof SVGElement) {
8919                 return className && (' '+this.dom.className.baseVal +' ').indexOf(' '+className+' ') != -1; 
8920             } 
8921             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
8922         },
8923
8924         /**
8925          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
8926          * @param {String} oldClassName The CSS class to replace
8927          * @param {String} newClassName The replacement CSS class
8928          * @return {Roo.Element} this
8929          */
8930         replaceClass : function(oldClassName, newClassName){
8931             this.removeClass(oldClassName);
8932             this.addClass(newClassName);
8933             return this;
8934         },
8935
8936         /**
8937          * Returns an object with properties matching the styles requested.
8938          * For example, el.getStyles('color', 'font-size', 'width') might return
8939          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
8940          * @param {String} style1 A style name
8941          * @param {String} style2 A style name
8942          * @param {String} etc.
8943          * @return {Object} The style object
8944          */
8945         getStyles : function(){
8946             var a = arguments, len = a.length, r = {};
8947             for(var i = 0; i < len; i++){
8948                 r[a[i]] = this.getStyle(a[i]);
8949             }
8950             return r;
8951         },
8952
8953         /**
8954          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
8955          * @param {String} property The style property whose value is returned.
8956          * @return {String} The current value of the style property for this element.
8957          */
8958         getStyle : function(){
8959             return view && view.getComputedStyle ?
8960                 function(prop){
8961                     var el = this.dom, v, cs, camel;
8962                     if(prop == 'float'){
8963                         prop = "cssFloat";
8964                     }
8965                     if(el.style && (v = el.style[prop])){
8966                         return v;
8967                     }
8968                     if(cs = view.getComputedStyle(el, "")){
8969                         if(!(camel = propCache[prop])){
8970                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
8971                         }
8972                         return cs[camel];
8973                     }
8974                     return null;
8975                 } :
8976                 function(prop){
8977                     var el = this.dom, v, cs, camel;
8978                     if(prop == 'opacity'){
8979                         if(typeof el.style.filter == 'string'){
8980                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
8981                             if(m){
8982                                 var fv = parseFloat(m[1]);
8983                                 if(!isNaN(fv)){
8984                                     return fv ? fv / 100 : 0;
8985                                 }
8986                             }
8987                         }
8988                         return 1;
8989                     }else if(prop == 'float'){
8990                         prop = "styleFloat";
8991                     }
8992                     if(!(camel = propCache[prop])){
8993                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
8994                     }
8995                     if(v = el.style[camel]){
8996                         return v;
8997                     }
8998                     if(cs = el.currentStyle){
8999                         return cs[camel];
9000                     }
9001                     return null;
9002                 };
9003         }(),
9004
9005         /**
9006          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
9007          * @param {String/Object} property The style property to be set, or an object of multiple styles.
9008          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
9009          * @return {Roo.Element} this
9010          */
9011         setStyle : function(prop, value){
9012             if(typeof prop == "string"){
9013                 
9014                 if (prop == 'float') {
9015                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
9016                     return this;
9017                 }
9018                 
9019                 var camel;
9020                 if(!(camel = propCache[prop])){
9021                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
9022                 }
9023                 
9024                 if(camel == 'opacity') {
9025                     this.setOpacity(value);
9026                 }else{
9027                     this.dom.style[camel] = value;
9028                 }
9029             }else{
9030                 for(var style in prop){
9031                     if(typeof prop[style] != "function"){
9032                        this.setStyle(style, prop[style]);
9033                     }
9034                 }
9035             }
9036             return this;
9037         },
9038
9039         /**
9040          * More flexible version of {@link #setStyle} for setting style properties.
9041          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
9042          * a function which returns such a specification.
9043          * @return {Roo.Element} this
9044          */
9045         applyStyles : function(style){
9046             Roo.DomHelper.applyStyles(this.dom, style);
9047             return this;
9048         },
9049
9050         /**
9051           * 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).
9052           * @return {Number} The X position of the element
9053           */
9054         getX : function(){
9055             return D.getX(this.dom);
9056         },
9057
9058         /**
9059           * 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).
9060           * @return {Number} The Y position of the element
9061           */
9062         getY : function(){
9063             return D.getY(this.dom);
9064         },
9065
9066         /**
9067           * 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).
9068           * @return {Array} The XY position of the element
9069           */
9070         getXY : function(){
9071             return D.getXY(this.dom);
9072         },
9073
9074         /**
9075          * 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).
9076          * @param {Number} The X position of the element
9077          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
9078          * @return {Roo.Element} this
9079          */
9080         setX : function(x, animate){
9081             if(!animate || !A){
9082                 D.setX(this.dom, x);
9083             }else{
9084                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
9085             }
9086             return this;
9087         },
9088
9089         /**
9090          * 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).
9091          * @param {Number} The Y position of the element
9092          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
9093          * @return {Roo.Element} this
9094          */
9095         setY : function(y, animate){
9096             if(!animate || !A){
9097                 D.setY(this.dom, y);
9098             }else{
9099                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
9100             }
9101             return this;
9102         },
9103
9104         /**
9105          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
9106          * @param {String} left The left CSS property value
9107          * @return {Roo.Element} this
9108          */
9109         setLeft : function(left){
9110             this.setStyle("left", this.addUnits(left));
9111             return this;
9112         },
9113
9114         /**
9115          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
9116          * @param {String} top The top CSS property value
9117          * @return {Roo.Element} this
9118          */
9119         setTop : function(top){
9120             this.setStyle("top", this.addUnits(top));
9121             return this;
9122         },
9123
9124         /**
9125          * Sets the element's CSS right style.
9126          * @param {String} right The right CSS property value
9127          * @return {Roo.Element} this
9128          */
9129         setRight : function(right){
9130             this.setStyle("right", this.addUnits(right));
9131             return this;
9132         },
9133
9134         /**
9135          * Sets the element's CSS bottom style.
9136          * @param {String} bottom The bottom CSS property value
9137          * @return {Roo.Element} this
9138          */
9139         setBottom : function(bottom){
9140             this.setStyle("bottom", this.addUnits(bottom));
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 {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
9148          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
9149          * @return {Roo.Element} this
9150          */
9151         setXY : function(pos, animate){
9152             if(!animate || !A){
9153                 D.setXY(this.dom, pos);
9154             }else{
9155                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
9156             }
9157             return this;
9158         },
9159
9160         /**
9161          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
9162          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
9163          * @param {Number} x X value for new position (coordinates are page-based)
9164          * @param {Number} y Y value for new position (coordinates are page-based)
9165          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
9166          * @return {Roo.Element} this
9167          */
9168         setLocation : function(x, y, animate){
9169             this.setXY([x, y], this.preanim(arguments, 2));
9170             return this;
9171         },
9172
9173         /**
9174          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
9175          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
9176          * @param {Number} x X value for new position (coordinates are page-based)
9177          * @param {Number} y Y value for new position (coordinates are page-based)
9178          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
9179          * @return {Roo.Element} this
9180          */
9181         moveTo : function(x, y, animate){
9182             this.setXY([x, y], this.preanim(arguments, 2));
9183             return this;
9184         },
9185
9186         /**
9187          * Returns the region of the given element.
9188          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
9189          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
9190          */
9191         getRegion : function(){
9192             return D.getRegion(this.dom);
9193         },
9194
9195         /**
9196          * Returns the offset height of the element
9197          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
9198          * @return {Number} The element's height
9199          */
9200         getHeight : function(contentHeight){
9201             var h = this.dom.offsetHeight || 0;
9202             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
9203         },
9204
9205         /**
9206          * Returns the offset width of the element
9207          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
9208          * @return {Number} The element's width
9209          */
9210         getWidth : function(contentWidth){
9211             var w = this.dom.offsetWidth || 0;
9212             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
9213         },
9214
9215         /**
9216          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
9217          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
9218          * if a height has not been set using CSS.
9219          * @return {Number}
9220          */
9221         getComputedHeight : function(){
9222             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
9223             if(!h){
9224                 h = parseInt(this.getStyle('height'), 10) || 0;
9225                 if(!this.isBorderBox()){
9226                     h += this.getFrameWidth('tb');
9227                 }
9228             }
9229             return h;
9230         },
9231
9232         /**
9233          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
9234          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
9235          * if a width has not been set using CSS.
9236          * @return {Number}
9237          */
9238         getComputedWidth : function(){
9239             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
9240             if(!w){
9241                 w = parseInt(this.getStyle('width'), 10) || 0;
9242                 if(!this.isBorderBox()){
9243                     w += this.getFrameWidth('lr');
9244                 }
9245             }
9246             return w;
9247         },
9248
9249         /**
9250          * Returns the size of the element.
9251          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
9252          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
9253          */
9254         getSize : function(contentSize){
9255             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
9256         },
9257
9258         /**
9259          * Returns the width and height of the viewport.
9260          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
9261          */
9262         getViewSize : function(){
9263             var d = this.dom, doc = document, aw = 0, ah = 0;
9264             if(d == doc || d == doc.body){
9265                 return {width : D.getViewWidth(), height: D.getViewHeight()};
9266             }else{
9267                 return {
9268                     width : d.clientWidth,
9269                     height: d.clientHeight
9270                 };
9271             }
9272         },
9273
9274         /**
9275          * Returns the value of the "value" attribute
9276          * @param {Boolean} asNumber true to parse the value as a number
9277          * @return {String/Number}
9278          */
9279         getValue : function(asNumber){
9280             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
9281         },
9282
9283         // private
9284         adjustWidth : function(width){
9285             if(typeof width == "number"){
9286                 if(this.autoBoxAdjust && !this.isBorderBox()){
9287                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
9288                 }
9289                 if(width < 0){
9290                     width = 0;
9291                 }
9292             }
9293             return width;
9294         },
9295
9296         // private
9297         adjustHeight : function(height){
9298             if(typeof height == "number"){
9299                if(this.autoBoxAdjust && !this.isBorderBox()){
9300                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
9301                }
9302                if(height < 0){
9303                    height = 0;
9304                }
9305             }
9306             return height;
9307         },
9308
9309         /**
9310          * Set the width of the element
9311          * @param {Number} width The new width
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         setWidth : function(width, animate){
9316             width = this.adjustWidth(width);
9317             if(!animate || !A){
9318                 this.dom.style.width = this.addUnits(width);
9319             }else{
9320                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
9321             }
9322             return this;
9323         },
9324
9325         /**
9326          * Set the height of the element
9327          * @param {Number} height The new height
9328          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9329          * @return {Roo.Element} this
9330          */
9331          setHeight : function(height, animate){
9332             height = this.adjustHeight(height);
9333             if(!animate || !A){
9334                 this.dom.style.height = this.addUnits(height);
9335             }else{
9336                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
9337             }
9338             return this;
9339         },
9340
9341         /**
9342          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
9343          * @param {Number} width The new width
9344          * @param {Number} height The new height
9345          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9346          * @return {Roo.Element} this
9347          */
9348          setSize : function(width, height, animate){
9349             if(typeof width == "object"){ // in case of object from getSize()
9350                 height = width.height; width = width.width;
9351             }
9352             width = this.adjustWidth(width); height = this.adjustHeight(height);
9353             if(!animate || !A){
9354                 this.dom.style.width = this.addUnits(width);
9355                 this.dom.style.height = this.addUnits(height);
9356             }else{
9357                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
9358             }
9359             return this;
9360         },
9361
9362         /**
9363          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
9364          * @param {Number} x X value for new position (coordinates are page-based)
9365          * @param {Number} y Y value for new position (coordinates are page-based)
9366          * @param {Number} width The new width
9367          * @param {Number} height The new height
9368          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9369          * @return {Roo.Element} this
9370          */
9371         setBounds : function(x, y, width, height, animate){
9372             if(!animate || !A){
9373                 this.setSize(width, height);
9374                 this.setLocation(x, y);
9375             }else{
9376                 width = this.adjustWidth(width); height = this.adjustHeight(height);
9377                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
9378                               this.preanim(arguments, 4), 'motion');
9379             }
9380             return this;
9381         },
9382
9383         /**
9384          * 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.
9385          * @param {Roo.lib.Region} region The region to fill
9386          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9387          * @return {Roo.Element} this
9388          */
9389         setRegion : function(region, animate){
9390             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
9391             return this;
9392         },
9393
9394         /**
9395          * Appends an event handler
9396          *
9397          * @param {String}   eventName     The type of event to append
9398          * @param {Function} fn        The method the event invokes
9399          * @param {Object} scope       (optional) The scope (this object) of the fn
9400          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9401          */
9402         addListener : function(eventName, fn, scope, options)
9403         {
9404             if (eventName == 'dblclick') { // doublclick (touchstart) - faked on touch.
9405                 this.addListener('touchstart', this.onTapHandler, this);
9406             }
9407             
9408             // we need to handle a special case where dom element is a svg element.
9409             // in this case we do not actua
9410             if (!this.dom) {
9411                 return;
9412             }
9413             
9414             if (this.dom instanceof SVGElement && !(this.dom instanceof SVGSVGElement)) {
9415                 if (typeof(this.listeners[eventName]) == 'undefined') {
9416                     this.listeners[eventName] =  new Roo.util.Event(this, eventName);
9417                 }
9418                 this.listeners[eventName].addListener(fn, scope, options);
9419                 return;
9420             }
9421             
9422                 
9423             Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
9424             
9425             
9426         },
9427         tapedTwice : false,
9428         onTapHandler : function(event)
9429         {
9430             if(!this.tapedTwice) {
9431                 this.tapedTwice = true;
9432                 var s = this;
9433                 setTimeout( function() {
9434                     s.tapedTwice = false;
9435                 }, 300 );
9436                 return;
9437             }
9438             event.preventDefault();
9439             var revent = new MouseEvent('dblclick',  {
9440                 view: window,
9441                 bubbles: true,
9442                 cancelable: true
9443             });
9444              
9445             this.dom.dispatchEvent(revent);
9446             //action on double tap goes below
9447              
9448         }, 
9449  
9450         /**
9451          * Removes an event handler from this element
9452          * @param {String} eventName the type of event to remove
9453          * @param {Function} fn the method the event invokes
9454          * @param {Function} scope (needed for svg fake listeners)
9455          * @return {Roo.Element} this
9456          */
9457         removeListener : function(eventName, fn, scope){
9458             Roo.EventManager.removeListener(this.dom,  eventName, fn);
9459             if (typeof(this.listeners) == 'undefined'  || typeof(this.listeners[eventName]) == 'undefined') {
9460                 return this;
9461             }
9462             this.listeners[eventName].removeListener(fn, scope);
9463             return this;
9464         },
9465
9466         /**
9467          * Removes all previous added listeners from this element
9468          * @return {Roo.Element} this
9469          */
9470         removeAllListeners : function(){
9471             E.purgeElement(this.dom);
9472             this.listeners = {};
9473             return this;
9474         },
9475
9476         relayEvent : function(eventName, observable){
9477             this.on(eventName, function(e){
9478                 observable.fireEvent(eventName, e);
9479             });
9480         },
9481
9482         
9483         /**
9484          * Set the opacity of the element
9485          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
9486          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9487          * @return {Roo.Element} this
9488          */
9489          setOpacity : function(opacity, animate){
9490             if(!animate || !A){
9491                 var s = this.dom.style;
9492                 if(Roo.isIE){
9493                     s.zoom = 1;
9494                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
9495                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
9496                 }else{
9497                     s.opacity = opacity;
9498                 }
9499             }else{
9500                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
9501             }
9502             return this;
9503         },
9504
9505         /**
9506          * Gets the left X coordinate
9507          * @param {Boolean} local True to get the local css position instead of page coordinate
9508          * @return {Number}
9509          */
9510         getLeft : function(local){
9511             if(!local){
9512                 return this.getX();
9513             }else{
9514                 return parseInt(this.getStyle("left"), 10) || 0;
9515             }
9516         },
9517
9518         /**
9519          * Gets the right X coordinate of the element (element X position + element width)
9520          * @param {Boolean} local True to get the local css position instead of page coordinate
9521          * @return {Number}
9522          */
9523         getRight : function(local){
9524             if(!local){
9525                 return this.getX() + this.getWidth();
9526             }else{
9527                 return (this.getLeft(true) + this.getWidth()) || 0;
9528             }
9529         },
9530
9531         /**
9532          * Gets the top Y coordinate
9533          * @param {Boolean} local True to get the local css position instead of page coordinate
9534          * @return {Number}
9535          */
9536         getTop : function(local) {
9537             if(!local){
9538                 return this.getY();
9539             }else{
9540                 return parseInt(this.getStyle("top"), 10) || 0;
9541             }
9542         },
9543
9544         /**
9545          * Gets the bottom Y coordinate of the element (element Y position + element height)
9546          * @param {Boolean} local True to get the local css position instead of page coordinate
9547          * @return {Number}
9548          */
9549         getBottom : function(local){
9550             if(!local){
9551                 return this.getY() + this.getHeight();
9552             }else{
9553                 return (this.getTop(true) + this.getHeight()) || 0;
9554             }
9555         },
9556
9557         /**
9558         * Initializes positioning on this element. If a desired position is not passed, it will make the
9559         * the element positioned relative IF it is not already positioned.
9560         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
9561         * @param {Number} zIndex (optional) The zIndex to apply
9562         * @param {Number} x (optional) Set the page X position
9563         * @param {Number} y (optional) Set the page Y position
9564         */
9565         position : function(pos, zIndex, x, y){
9566             if(!pos){
9567                if(this.getStyle('position') == 'static'){
9568                    this.setStyle('position', 'relative');
9569                }
9570             }else{
9571                 this.setStyle("position", pos);
9572             }
9573             if(zIndex){
9574                 this.setStyle("z-index", zIndex);
9575             }
9576             if(x !== undefined && y !== undefined){
9577                 this.setXY([x, y]);
9578             }else if(x !== undefined){
9579                 this.setX(x);
9580             }else if(y !== undefined){
9581                 this.setY(y);
9582             }
9583         },
9584
9585         /**
9586         * Clear positioning back to the default when the document was loaded
9587         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
9588         * @return {Roo.Element} this
9589          */
9590         clearPositioning : function(value){
9591             value = value ||'';
9592             this.setStyle({
9593                 "left": value,
9594                 "right": value,
9595                 "top": value,
9596                 "bottom": value,
9597                 "z-index": "",
9598                 "position" : "static"
9599             });
9600             return this;
9601         },
9602
9603         /**
9604         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
9605         * snapshot before performing an update and then restoring the element.
9606         * @return {Object}
9607         */
9608         getPositioning : function(){
9609             var l = this.getStyle("left");
9610             var t = this.getStyle("top");
9611             return {
9612                 "position" : this.getStyle("position"),
9613                 "left" : l,
9614                 "right" : l ? "" : this.getStyle("right"),
9615                 "top" : t,
9616                 "bottom" : t ? "" : this.getStyle("bottom"),
9617                 "z-index" : this.getStyle("z-index")
9618             };
9619         },
9620
9621         /**
9622          * Gets the width of the border(s) for the specified side(s)
9623          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
9624          * passing lr would get the border (l)eft width + the border (r)ight width.
9625          * @return {Number} The width of the sides passed added together
9626          */
9627         getBorderWidth : function(side){
9628             return this.addStyles(side, El.borders);
9629         },
9630
9631         /**
9632          * Gets the width of the padding(s) for the specified side(s)
9633          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
9634          * passing lr would get the padding (l)eft + the padding (r)ight.
9635          * @return {Number} The padding of the sides passed added together
9636          */
9637         getPadding : function(side){
9638             return this.addStyles(side, El.paddings);
9639         },
9640
9641         /**
9642         * Set positioning with an object returned by getPositioning().
9643         * @param {Object} posCfg
9644         * @return {Roo.Element} this
9645          */
9646         setPositioning : function(pc){
9647             this.applyStyles(pc);
9648             if(pc.right == "auto"){
9649                 this.dom.style.right = "";
9650             }
9651             if(pc.bottom == "auto"){
9652                 this.dom.style.bottom = "";
9653             }
9654             return this;
9655         },
9656
9657         // private
9658         fixDisplay : function(){
9659             if(this.getStyle("display") == "none"){
9660                 this.setStyle("visibility", "hidden");
9661                 this.setStyle("display", this.originalDisplay); // first try reverting to default
9662                 if(this.getStyle("display") == "none"){ // if that fails, default to block
9663                     this.setStyle("display", "block");
9664                 }
9665             }
9666         },
9667
9668         /**
9669          * Quick set left and top adding default units
9670          * @param {String} left The left CSS property value
9671          * @param {String} top The top CSS property value
9672          * @return {Roo.Element} this
9673          */
9674          setLeftTop : function(left, top){
9675             this.dom.style.left = this.addUnits(left);
9676             this.dom.style.top = this.addUnits(top);
9677             return this;
9678         },
9679
9680         /**
9681          * Move this element relative to its current position.
9682          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9683          * @param {Number} distance How far to move the element in pixels
9684          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9685          * @return {Roo.Element} this
9686          */
9687          move : function(direction, distance, animate){
9688             var xy = this.getXY();
9689             direction = direction.toLowerCase();
9690             switch(direction){
9691                 case "l":
9692                 case "left":
9693                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
9694                     break;
9695                case "r":
9696                case "right":
9697                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
9698                     break;
9699                case "t":
9700                case "top":
9701                case "up":
9702                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
9703                     break;
9704                case "b":
9705                case "bottom":
9706                case "down":
9707                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
9708                     break;
9709             }
9710             return this;
9711         },
9712
9713         /**
9714          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
9715          * @return {Roo.Element} this
9716          */
9717         clip : function(){
9718             if(!this.isClipped){
9719                this.isClipped = true;
9720                this.originalClip = {
9721                    "o": this.getStyle("overflow"),
9722                    "x": this.getStyle("overflow-x"),
9723                    "y": this.getStyle("overflow-y")
9724                };
9725                this.setStyle("overflow", "hidden");
9726                this.setStyle("overflow-x", "hidden");
9727                this.setStyle("overflow-y", "hidden");
9728             }
9729             return this;
9730         },
9731
9732         /**
9733          *  Return clipping (overflow) to original clipping before clip() was called
9734          * @return {Roo.Element} this
9735          */
9736         unclip : function(){
9737             if(this.isClipped){
9738                 this.isClipped = false;
9739                 var o = this.originalClip;
9740                 if(o.o){this.setStyle("overflow", o.o);}
9741                 if(o.x){this.setStyle("overflow-x", o.x);}
9742                 if(o.y){this.setStyle("overflow-y", o.y);}
9743             }
9744             return this;
9745         },
9746
9747
9748         /**
9749          * Gets the x,y coordinates specified by the anchor position on the element.
9750          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
9751          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
9752          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
9753          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
9754          * @return {Array} [x, y] An array containing the element's x and y coordinates
9755          */
9756         getAnchorXY : function(anchor, local, s){
9757             //Passing a different size is useful for pre-calculating anchors,
9758             //especially for anchored animations that change the el size.
9759
9760             var w, h, vp = false;
9761             if(!s){
9762                 var d = this.dom;
9763                 if(d == document.body || d == document){
9764                     vp = true;
9765                     w = D.getViewWidth(); h = D.getViewHeight();
9766                 }else{
9767                     w = this.getWidth(); h = this.getHeight();
9768                 }
9769             }else{
9770                 w = s.width;  h = s.height;
9771             }
9772             var x = 0, y = 0, r = Math.round;
9773             switch((anchor || "tl").toLowerCase()){
9774                 case "c":
9775                     x = r(w*.5);
9776                     y = r(h*.5);
9777                 break;
9778                 case "t":
9779                     x = r(w*.5);
9780                     y = 0;
9781                 break;
9782                 case "l":
9783                     x = 0;
9784                     y = r(h*.5);
9785                 break;
9786                 case "r":
9787                     x = w;
9788                     y = r(h*.5);
9789                 break;
9790                 case "b":
9791                     x = r(w*.5);
9792                     y = h;
9793                 break;
9794                 case "tl":
9795                     x = 0;
9796                     y = 0;
9797                 break;
9798                 case "bl":
9799                     x = 0;
9800                     y = h;
9801                 break;
9802                 case "br":
9803                     x = w;
9804                     y = h;
9805                 break;
9806                 case "tr":
9807                     x = w;
9808                     y = 0;
9809                 break;
9810             }
9811             if(local === true){
9812                 return [x, y];
9813             }
9814             if(vp){
9815                 var sc = this.getScroll();
9816                 return [x + sc.left, y + sc.top];
9817             }
9818             //Add the element's offset xy
9819             var o = this.getXY();
9820             return [x+o[0], y+o[1]];
9821         },
9822
9823         /**
9824          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
9825          * supported position values.
9826          * @param {String/HTMLElement/Roo.Element} element The element to align to.
9827          * @param {String} position The position to align to.
9828          * @param {Array} offsets (optional) Offset the positioning by [x, y]
9829          * @return {Array} [x, y]
9830          */
9831         getAlignToXY : function(el, p, o)
9832         {
9833             el = Roo.get(el);
9834             var d = this.dom;
9835             if(!el.dom){
9836                 throw "Element.alignTo with an element that doesn't exist";
9837             }
9838             var c = false; //constrain to viewport
9839             var p1 = "", p2 = "";
9840             o = o || [0,0];
9841
9842             if(!p){
9843                 p = "tl-bl";
9844             }else if(p == "?"){
9845                 p = "tl-bl?";
9846             }else if(p.indexOf("-") == -1){
9847                 p = "tl-" + p;
9848             }
9849             p = p.toLowerCase();
9850             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
9851             if(!m){
9852                throw "Element.alignTo with an invalid alignment " + p;
9853             }
9854             p1 = m[1]; p2 = m[2]; c = !!m[3];
9855
9856             //Subtract the aligned el's internal xy from the target's offset xy
9857             //plus custom offset to get the aligned el's new offset xy
9858             var a1 = this.getAnchorXY(p1, true);
9859             var a2 = el.getAnchorXY(p2, false);
9860             var x = a2[0] - a1[0] + o[0];
9861             var y = a2[1] - a1[1] + o[1];
9862             if(c){
9863                 //constrain the aligned el to viewport if necessary
9864                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
9865                 // 5px of margin for ie
9866                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
9867
9868                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
9869                 //perpendicular to the vp border, allow the aligned el to slide on that border,
9870                 //otherwise swap the aligned el to the opposite border of the target.
9871                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
9872                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
9873                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t")  );
9874                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
9875
9876                var doc = document;
9877                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
9878                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
9879
9880                if((x+w) > dw + scrollX){
9881                     x = swapX ? r.left-w : dw+scrollX-w;
9882                 }
9883                if(x < scrollX){
9884                    x = swapX ? r.right : scrollX;
9885                }
9886                if((y+h) > dh + scrollY){
9887                     y = swapY ? r.top-h : dh+scrollY-h;
9888                 }
9889                if (y < scrollY){
9890                    y = swapY ? r.bottom : scrollY;
9891                }
9892             }
9893             return [x,y];
9894         },
9895
9896         // private
9897         getConstrainToXY : function(){
9898             var os = {top:0, left:0, bottom:0, right: 0};
9899
9900             return function(el, local, offsets, proposedXY){
9901                 el = Roo.get(el);
9902                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
9903
9904                 var vw, vh, vx = 0, vy = 0;
9905                 if(el.dom == document.body || el.dom == document){
9906                     vw = Roo.lib.Dom.getViewWidth();
9907                     vh = Roo.lib.Dom.getViewHeight();
9908                 }else{
9909                     vw = el.dom.clientWidth;
9910                     vh = el.dom.clientHeight;
9911                     if(!local){
9912                         var vxy = el.getXY();
9913                         vx = vxy[0];
9914                         vy = vxy[1];
9915                     }
9916                 }
9917
9918                 var s = el.getScroll();
9919
9920                 vx += offsets.left + s.left;
9921                 vy += offsets.top + s.top;
9922
9923                 vw -= offsets.right;
9924                 vh -= offsets.bottom;
9925
9926                 var vr = vx+vw;
9927                 var vb = vy+vh;
9928
9929                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
9930                 var x = xy[0], y = xy[1];
9931                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
9932
9933                 // only move it if it needs it
9934                 var moved = false;
9935
9936                 // first validate right/bottom
9937                 if((x + w) > vr){
9938                     x = vr - w;
9939                     moved = true;
9940                 }
9941                 if((y + h) > vb){
9942                     y = vb - h;
9943                     moved = true;
9944                 }
9945                 // then make sure top/left isn't negative
9946                 if(x < vx){
9947                     x = vx;
9948                     moved = true;
9949                 }
9950                 if(y < vy){
9951                     y = vy;
9952                     moved = true;
9953                 }
9954                 return moved ? [x, y] : false;
9955             };
9956         }(),
9957
9958         // private
9959         adjustForConstraints : function(xy, parent, offsets){
9960             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
9961         },
9962
9963         /**
9964          * Aligns this element with another element relative to the specified anchor points. If the other element is the
9965          * document it aligns it to the viewport.
9966          * The position parameter is optional, and can be specified in any one of the following formats:
9967          * <ul>
9968          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
9969          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
9970          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
9971          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
9972          *   <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
9973          *       element's anchor point, and the second value is used as the target's anchor point.</li>
9974          * </ul>
9975          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
9976          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
9977          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
9978          * that specified in order to enforce the viewport constraints.
9979          * Following are all of the supported anchor positions:
9980     <pre>
9981     Value  Description
9982     -----  -----------------------------
9983     tl     The top left corner (default)
9984     t      The center of the top edge
9985     tr     The top right corner
9986     l      The center of the left edge
9987     c      In the center of the element
9988     r      The center of the right edge
9989     bl     The bottom left corner
9990     b      The center of the bottom edge
9991     br     The bottom right corner
9992     </pre>
9993     Example Usage:
9994     <pre><code>
9995     // align el to other-el using the default positioning ("tl-bl", non-constrained)
9996     el.alignTo("other-el");
9997
9998     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
9999     el.alignTo("other-el", "tr?");
10000
10001     // align the bottom right corner of el with the center left edge of other-el
10002     el.alignTo("other-el", "br-l?");
10003
10004     // align the center of el with the bottom left corner of other-el and
10005     // adjust the x position by -6 pixels (and the y position by 0)
10006     el.alignTo("other-el", "c-bl", [-6, 0]);
10007     </code></pre>
10008          * @param {String/HTMLElement/Roo.Element} element The element to align to.
10009          * @param {String} position The position to align to.
10010          * @param {Array} offsets (optional) Offset the positioning by [x, y]
10011          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10012          * @return {Roo.Element} this
10013          */
10014         alignTo : function(element, position, offsets, animate){
10015             var xy = this.getAlignToXY(element, position, offsets);
10016             this.setXY(xy, this.preanim(arguments, 3));
10017             return this;
10018         },
10019
10020         /**
10021          * Anchors an element to another element and realigns it when the window is resized.
10022          * @param {String/HTMLElement/Roo.Element} element The element to align to.
10023          * @param {String} position The position to align to.
10024          * @param {Array} offsets (optional) Offset the positioning by [x, y]
10025          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
10026          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
10027          * is a number, it is used as the buffer delay (defaults to 50ms).
10028          * @param {Function} callback The function to call after the animation finishes
10029          * @return {Roo.Element} this
10030          */
10031         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
10032             var action = function(){
10033                 this.alignTo(el, alignment, offsets, animate);
10034                 Roo.callback(callback, this);
10035             };
10036             Roo.EventManager.onWindowResize(action, this);
10037             var tm = typeof monitorScroll;
10038             if(tm != 'undefined'){
10039                 Roo.EventManager.on(window, 'scroll', action, this,
10040                     {buffer: tm == 'number' ? monitorScroll : 50});
10041             }
10042             action.call(this); // align immediately
10043             return this;
10044         },
10045         /**
10046          * Clears any opacity settings from this element. Required in some cases for IE.
10047          * @return {Roo.Element} this
10048          */
10049         clearOpacity : function(){
10050             if (window.ActiveXObject) {
10051                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
10052                     this.dom.style.filter = "";
10053                 }
10054             } else {
10055                 this.dom.style.opacity = "";
10056                 this.dom.style["-moz-opacity"] = "";
10057                 this.dom.style["-khtml-opacity"] = "";
10058             }
10059             return this;
10060         },
10061
10062         /**
10063          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
10064          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10065          * @return {Roo.Element} this
10066          */
10067         hide : function(animate){
10068             this.setVisible(false, this.preanim(arguments, 0));
10069             return this;
10070         },
10071
10072         /**
10073         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
10074         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10075          * @return {Roo.Element} this
10076          */
10077         show : function(animate){
10078             this.setVisible(true, this.preanim(arguments, 0));
10079             return this;
10080         },
10081
10082         /**
10083          * @private Test if size has a unit, otherwise appends the default
10084          */
10085         addUnits : function(size){
10086             return Roo.Element.addUnits(size, this.defaultUnit);
10087         },
10088
10089         /**
10090          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
10091          * @return {Roo.Element} this
10092          */
10093         beginMeasure : function(){
10094             var el = this.dom;
10095             if(el.offsetWidth || el.offsetHeight){
10096                 return this; // offsets work already
10097             }
10098             var changed = [];
10099             var p = this.dom, b = document.body; // start with this element
10100             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
10101                 var pe = Roo.get(p);
10102                 if(pe.getStyle('display') == 'none'){
10103                     changed.push({el: p, visibility: pe.getStyle("visibility")});
10104                     p.style.visibility = "hidden";
10105                     p.style.display = "block";
10106                 }
10107                 p = p.parentNode;
10108             }
10109             this._measureChanged = changed;
10110             return this;
10111
10112         },
10113
10114         /**
10115          * Restores displays to before beginMeasure was called
10116          * @return {Roo.Element} this
10117          */
10118         endMeasure : function(){
10119             var changed = this._measureChanged;
10120             if(changed){
10121                 for(var i = 0, len = changed.length; i < len; i++) {
10122                     var r = changed[i];
10123                     r.el.style.visibility = r.visibility;
10124                     r.el.style.display = "none";
10125                 }
10126                 this._measureChanged = null;
10127             }
10128             return this;
10129         },
10130
10131         /**
10132         * Update the innerHTML of this element, optionally searching for and processing scripts
10133         * @param {String} html The new HTML
10134         * @param {Boolean} loadScripts (optional) true to look for and process scripts
10135         * @param {Function} callback For async script loading you can be noticed when the update completes
10136         * @return {Roo.Element} this
10137          */
10138         update : function(html, loadScripts, callback){
10139             if(typeof html == "undefined"){
10140                 html = "";
10141             }
10142             if(loadScripts !== true){
10143                 this.dom.innerHTML = html;
10144                 if(typeof callback == "function"){
10145                     callback();
10146                 }
10147                 return this;
10148             }
10149             var id = Roo.id();
10150             var dom = this.dom;
10151
10152             html += '<span id="' + id + '"></span>';
10153
10154             E.onAvailable(id, function(){
10155                 var hd = document.getElementsByTagName("head")[0];
10156                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
10157                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
10158                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
10159
10160                 var match;
10161                 while(match = re.exec(html)){
10162                     var attrs = match[1];
10163                     var srcMatch = attrs ? attrs.match(srcRe) : false;
10164                     if(srcMatch && srcMatch[2]){
10165                        var s = document.createElement("script");
10166                        s.src = srcMatch[2];
10167                        var typeMatch = attrs.match(typeRe);
10168                        if(typeMatch && typeMatch[2]){
10169                            s.type = typeMatch[2];
10170                        }
10171                        hd.appendChild(s);
10172                     }else if(match[2] && match[2].length > 0){
10173                         if(window.execScript) {
10174                            window.execScript(match[2]);
10175                         } else {
10176                             /**
10177                              * eval:var:id
10178                              * eval:var:dom
10179                              * eval:var:html
10180                              * 
10181                              */
10182                            window.eval(match[2]);
10183                         }
10184                     }
10185                 }
10186                 var el = document.getElementById(id);
10187                 if(el){el.parentNode.removeChild(el);}
10188                 if(typeof callback == "function"){
10189                     callback();
10190                 }
10191             });
10192             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
10193             return this;
10194         },
10195
10196         /**
10197          * Direct access to the UpdateManager update() method (takes the same parameters).
10198          * @param {String/Function} url The url for this request or a function to call to get the url
10199          * @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}
10200          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
10201          * @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.
10202          * @return {Roo.Element} this
10203          */
10204         load : function(){
10205             var um = this.getUpdateManager();
10206             um.update.apply(um, arguments);
10207             return this;
10208         },
10209
10210         /**
10211         * Gets this element's UpdateManager
10212         * @return {Roo.UpdateManager} The UpdateManager
10213         */
10214         getUpdateManager : function(){
10215             if(!this.updateManager){
10216                 this.updateManager = new Roo.UpdateManager(this);
10217             }
10218             return this.updateManager;
10219         },
10220
10221         /**
10222          * Disables text selection for this element (normalized across browsers)
10223          * @return {Roo.Element} this
10224          */
10225         unselectable : function(){
10226             this.dom.unselectable = "on";
10227             this.swallowEvent("selectstart", true);
10228             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
10229             this.addClass("x-unselectable");
10230             return this;
10231         },
10232
10233         /**
10234         * Calculates the x, y to center this element on the screen
10235         * @return {Array} The x, y values [x, y]
10236         */
10237         getCenterXY : function(){
10238             return this.getAlignToXY(document, 'c-c');
10239         },
10240
10241         /**
10242         * Centers the Element in either the viewport, or another Element.
10243         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
10244         */
10245         center : function(centerIn){
10246             this.alignTo(centerIn || document, 'c-c');
10247             return this;
10248         },
10249
10250         /**
10251          * Tests various css rules/browsers to determine if this element uses a border box
10252          * @return {Boolean}
10253          */
10254         isBorderBox : function(){
10255             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
10256         },
10257
10258         /**
10259          * Return a box {x, y, width, height} that can be used to set another elements
10260          * size/location to match this element.
10261          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
10262          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
10263          * @return {Object} box An object in the format {x, y, width, height}
10264          */
10265         getBox : function(contentBox, local){
10266             var xy;
10267             if(!local){
10268                 xy = this.getXY();
10269             }else{
10270                 var left = parseInt(this.getStyle("left"), 10) || 0;
10271                 var top = parseInt(this.getStyle("top"), 10) || 0;
10272                 xy = [left, top];
10273             }
10274             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
10275             if(!contentBox){
10276                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
10277             }else{
10278                 var l = this.getBorderWidth("l")+this.getPadding("l");
10279                 var r = this.getBorderWidth("r")+this.getPadding("r");
10280                 var t = this.getBorderWidth("t")+this.getPadding("t");
10281                 var b = this.getBorderWidth("b")+this.getPadding("b");
10282                 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)};
10283             }
10284             bx.right = bx.x + bx.width;
10285             bx.bottom = bx.y + bx.height;
10286             return bx;
10287         },
10288
10289         /**
10290          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
10291          for more information about the sides.
10292          * @param {String} sides
10293          * @return {Number}
10294          */
10295         getFrameWidth : function(sides, onlyContentBox){
10296             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
10297         },
10298
10299         /**
10300          * 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.
10301          * @param {Object} box The box to fill {x, y, width, height}
10302          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
10303          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10304          * @return {Roo.Element} this
10305          */
10306         setBox : function(box, adjust, animate){
10307             var w = box.width, h = box.height;
10308             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
10309                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
10310                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
10311             }
10312             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
10313             return this;
10314         },
10315
10316         /**
10317          * Forces the browser to repaint this element
10318          * @return {Roo.Element} this
10319          */
10320          repaint : function(){
10321             var dom = this.dom;
10322             this.addClass("x-repaint");
10323             setTimeout(function(){
10324                 Roo.get(dom).removeClass("x-repaint");
10325             }, 1);
10326             return this;
10327         },
10328
10329         /**
10330          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
10331          * then it returns the calculated width of the sides (see getPadding)
10332          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
10333          * @return {Object/Number}
10334          */
10335         getMargins : function(side){
10336             if(!side){
10337                 return {
10338                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
10339                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
10340                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
10341                     right: parseInt(this.getStyle("margin-right"), 10) || 0
10342                 };
10343             }else{
10344                 return this.addStyles(side, El.margins);
10345              }
10346         },
10347
10348         // private
10349         addStyles : function(sides, styles){
10350             var val = 0, v, w;
10351             for(var i = 0, len = sides.length; i < len; i++){
10352                 v = this.getStyle(styles[sides.charAt(i)]);
10353                 if(v){
10354                      w = parseInt(v, 10);
10355                      if(w){ val += w; }
10356                 }
10357             }
10358             return val;
10359         },
10360
10361         /**
10362          * Creates a proxy element of this element
10363          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
10364          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
10365          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
10366          * @return {Roo.Element} The new proxy element
10367          */
10368         createProxy : function(config, renderTo, matchBox){
10369             if(renderTo){
10370                 renderTo = Roo.getDom(renderTo);
10371             }else{
10372                 renderTo = document.body;
10373             }
10374             config = typeof config == "object" ?
10375                 config : {tag : "div", cls: config};
10376             var proxy = Roo.DomHelper.append(renderTo, config, true);
10377             if(matchBox){
10378                proxy.setBox(this.getBox());
10379             }
10380             return proxy;
10381         },
10382
10383         /**
10384          * Puts a mask over this element to disable user interaction. Requires core.css.
10385          * This method can only be applied to elements which accept child nodes.
10386          * @param {String} msg (optional) A message to display in the mask
10387          * @param {String} msgCls (optional) A css class to apply to the msg element - use no-spinner to hide the spinner on bootstrap
10388          * @return {Element} The mask  element
10389          */
10390         mask : function(msg, msgCls)
10391         {
10392             if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
10393                 this.setStyle("position", "relative");
10394             }
10395             if(!this._mask){
10396                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
10397             }
10398             
10399             this.addClass("x-masked");
10400             this._mask.setDisplayed(true);
10401             
10402             // we wander
10403             var z = 0;
10404             var dom = this.dom;
10405             while (dom && dom.style) {
10406                 if (!isNaN(parseInt(dom.style.zIndex))) {
10407                     z = Math.max(z, parseInt(dom.style.zIndex));
10408                 }
10409                 dom = dom.parentNode;
10410             }
10411             // if we are masking the body - then it hides everything..
10412             if (this.dom == document.body) {
10413                 z = 1000000;
10414                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
10415                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
10416             }
10417            
10418             if(typeof msg == 'string'){
10419                 if(!this._maskMsg){
10420                     this._maskMsg = Roo.DomHelper.append(this.dom, {
10421                         cls: "roo-el-mask-msg", 
10422                         cn: [
10423                             {
10424                                 tag: 'i',
10425                                 cls: 'fa fa-spinner fa-spin'
10426                             },
10427                             {
10428                                 tag: 'div'
10429                             }   
10430                         ]
10431                     }, true);
10432                 }
10433                 var mm = this._maskMsg;
10434                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
10435                 if (mm.dom.lastChild) { // weird IE issue?
10436                     mm.dom.lastChild.innerHTML = msg;
10437                 }
10438                 mm.setDisplayed(true);
10439                 mm.center(this);
10440                 mm.setStyle('z-index', z + 102);
10441             }
10442             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
10443                 this._mask.setHeight(this.getHeight());
10444             }
10445             this._mask.setStyle('z-index', z + 100);
10446             
10447             return this._mask;
10448         },
10449
10450         /**
10451          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
10452          * it is cached for reuse.
10453          */
10454         unmask : function(removeEl){
10455             if(this._mask){
10456                 if(removeEl === true){
10457                     this._mask.remove();
10458                     delete this._mask;
10459                     if(this._maskMsg){
10460                         this._maskMsg.remove();
10461                         delete this._maskMsg;
10462                     }
10463                 }else{
10464                     this._mask.setDisplayed(false);
10465                     if(this._maskMsg){
10466                         this._maskMsg.setDisplayed(false);
10467                     }
10468                 }
10469             }
10470             this.removeClass("x-masked");
10471         },
10472
10473         /**
10474          * Returns true if this element is masked
10475          * @return {Boolean}
10476          */
10477         isMasked : function(){
10478             return this._mask && this._mask.isVisible();
10479         },
10480
10481         /**
10482          * Creates an iframe shim for this element to keep selects and other windowed objects from
10483          * showing through.
10484          * @return {Roo.Element} The new shim element
10485          */
10486         createShim : function(){
10487             var el = document.createElement('iframe');
10488             el.frameBorder = 'no';
10489             el.className = 'roo-shim';
10490             if(Roo.isIE && Roo.isSecure){
10491                 el.src = Roo.SSL_SECURE_URL;
10492             }
10493             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
10494             shim.autoBoxAdjust = false;
10495             return shim;
10496         },
10497
10498         /**
10499          * Removes this element from the DOM and deletes it from the cache
10500          */
10501         remove : function(){
10502             if(this.dom.parentNode){
10503                 this.dom.parentNode.removeChild(this.dom);
10504             }
10505             delete El.cache[this.dom.id];
10506         },
10507
10508         /**
10509          * Sets up event handlers to add and remove a css class when the mouse is over this element
10510          * @param {String} className
10511          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
10512          * mouseout events for children elements
10513          * @return {Roo.Element} this
10514          */
10515         addClassOnOver : function(className, preventFlicker){
10516             this.on("mouseover", function(){
10517                 Roo.fly(this, '_internal').addClass(className);
10518             }, this.dom);
10519             var removeFn = function(e){
10520                 if(preventFlicker !== true || !e.within(this, true)){
10521                     Roo.fly(this, '_internal').removeClass(className);
10522                 }
10523             };
10524             this.on("mouseout", removeFn, this.dom);
10525             return this;
10526         },
10527
10528         /**
10529          * Sets up event handlers to add and remove a css class when this element has the focus
10530          * @param {String} className
10531          * @return {Roo.Element} this
10532          */
10533         addClassOnFocus : function(className){
10534             this.on("focus", function(){
10535                 Roo.fly(this, '_internal').addClass(className);
10536             }, this.dom);
10537             this.on("blur", function(){
10538                 Roo.fly(this, '_internal').removeClass(className);
10539             }, this.dom);
10540             return this;
10541         },
10542         /**
10543          * 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)
10544          * @param {String} className
10545          * @return {Roo.Element} this
10546          */
10547         addClassOnClick : function(className){
10548             var dom = this.dom;
10549             this.on("mousedown", function(){
10550                 Roo.fly(dom, '_internal').addClass(className);
10551                 var d = Roo.get(document);
10552                 var fn = function(){
10553                     Roo.fly(dom, '_internal').removeClass(className);
10554                     d.removeListener("mouseup", fn);
10555                 };
10556                 d.on("mouseup", fn);
10557             });
10558             return this;
10559         },
10560
10561         /**
10562          * Stops the specified event from bubbling and optionally prevents the default action
10563          * @param {String} eventName
10564          * @param {Boolean} preventDefault (optional) true to prevent the default action too
10565          * @return {Roo.Element} this
10566          */
10567         swallowEvent : function(eventName, preventDefault){
10568             var fn = function(e){
10569                 e.stopPropagation();
10570                 if(preventDefault){
10571                     e.preventDefault();
10572                 }
10573             };
10574             if(eventName instanceof Array){
10575                 for(var i = 0, len = eventName.length; i < len; i++){
10576                      this.on(eventName[i], fn);
10577                 }
10578                 return this;
10579             }
10580             this.on(eventName, fn);
10581             return this;
10582         },
10583
10584         /**
10585          * @private
10586          */
10587         fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
10588
10589         /**
10590          * Sizes this element to its parent element's dimensions performing
10591          * neccessary box adjustments.
10592          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
10593          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
10594          * @return {Roo.Element} this
10595          */
10596         fitToParent : function(monitorResize, targetParent) {
10597           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
10598           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
10599           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
10600             return this;
10601           }
10602           var p = Roo.get(targetParent || this.dom.parentNode);
10603           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
10604           if (monitorResize === true) {
10605             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
10606             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
10607           }
10608           return this;
10609         },
10610
10611         /**
10612          * Gets the next sibling, skipping text nodes
10613          * @return {HTMLElement} The next sibling or null
10614          */
10615         getNextSibling : function(){
10616             var n = this.dom.nextSibling;
10617             while(n && n.nodeType != 1){
10618                 n = n.nextSibling;
10619             }
10620             return n;
10621         },
10622
10623         /**
10624          * Gets the previous sibling, skipping text nodes
10625          * @return {HTMLElement} The previous sibling or null
10626          */
10627         getPrevSibling : function(){
10628             var n = this.dom.previousSibling;
10629             while(n && n.nodeType != 1){
10630                 n = n.previousSibling;
10631             }
10632             return n;
10633         },
10634
10635
10636         /**
10637          * Appends the passed element(s) to this element
10638          * @param {String/HTMLElement/Array/Element/CompositeElement} el
10639          * @return {Roo.Element} this
10640          */
10641         appendChild: function(el){
10642             el = Roo.get(el);
10643             el.appendTo(this);
10644             return this;
10645         },
10646
10647         /**
10648          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
10649          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
10650          * automatically generated with the specified attributes.
10651          * @param {HTMLElement} insertBefore (optional) a child element of this element
10652          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
10653          * @return {Roo.Element} The new child element
10654          */
10655         createChild: function(config, insertBefore, returnDom){
10656             config = config || {tag:'div'};
10657             if(insertBefore){
10658                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
10659             }
10660             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
10661         },
10662
10663         /**
10664          * Appends this element to the passed element
10665          * @param {String/HTMLElement/Element} el The new parent element
10666          * @return {Roo.Element} this
10667          */
10668         appendTo: function(el){
10669             el = Roo.getDom(el);
10670             el.appendChild(this.dom);
10671             return this;
10672         },
10673
10674         /**
10675          * Inserts this element before the passed element in the DOM
10676          * @param {String/HTMLElement/Element} el The element to insert before
10677          * @return {Roo.Element} this
10678          */
10679         insertBefore: function(el){
10680             el = Roo.getDom(el);
10681             el.parentNode.insertBefore(this.dom, el);
10682             return this;
10683         },
10684
10685         /**
10686          * Inserts this element after the passed element in the DOM
10687          * @param {String/HTMLElement/Element} el The element to insert after
10688          * @return {Roo.Element} this
10689          */
10690         insertAfter: function(el){
10691             el = Roo.getDom(el);
10692             el.parentNode.insertBefore(this.dom, el.nextSibling);
10693             return this;
10694         },
10695
10696         /**
10697          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
10698          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
10699          * @return {Roo.Element} The new child
10700          */
10701         insertFirst: function(el, returnDom){
10702             el = el || {};
10703             if(typeof el == 'object' && !el.nodeType){ // dh config
10704                 return this.createChild(el, this.dom.firstChild, returnDom);
10705             }else{
10706                 el = Roo.getDom(el);
10707                 this.dom.insertBefore(el, this.dom.firstChild);
10708                 return !returnDom ? Roo.get(el) : el;
10709             }
10710         },
10711
10712         /**
10713          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
10714          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
10715          * @param {String} where (optional) 'before' or 'after' defaults to before
10716          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
10717          * @return {Roo.Element} the inserted Element
10718          */
10719         insertSibling: function(el, where, returnDom){
10720             where = where ? where.toLowerCase() : 'before';
10721             el = el || {};
10722             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
10723
10724             if(typeof el == 'object' && !el.nodeType){ // dh config
10725                 if(where == 'after' && !this.dom.nextSibling){
10726                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
10727                 }else{
10728                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
10729                 }
10730
10731             }else{
10732                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
10733                             where == 'before' ? this.dom : this.dom.nextSibling);
10734                 if(!returnDom){
10735                     rt = Roo.get(rt);
10736                 }
10737             }
10738             return rt;
10739         },
10740
10741         /**
10742          * Creates and wraps this element with another element
10743          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
10744          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
10745          * @return {HTMLElement/Element} The newly created wrapper element
10746          */
10747         wrap: function(config, returnDom){
10748             if(!config){
10749                 config = {tag: "div"};
10750             }
10751             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
10752             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
10753             return newEl;
10754         },
10755
10756         /**
10757          * Replaces the passed element with this element
10758          * @param {String/HTMLElement/Element} el The element to replace
10759          * @return {Roo.Element} this
10760          */
10761         replace: function(el){
10762             el = Roo.get(el);
10763             this.insertBefore(el);
10764             el.remove();
10765             return this;
10766         },
10767
10768         /**
10769          * Inserts an html fragment into this element
10770          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
10771          * @param {String} html The HTML fragment
10772          * @param {Boolean} returnEl True to return an Roo.Element
10773          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
10774          */
10775         insertHtml : function(where, html, returnEl){
10776             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
10777             return returnEl ? Roo.get(el) : el;
10778         },
10779
10780         /**
10781          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
10782          * @param {Object} o The object with the attributes
10783          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
10784          * @return {Roo.Element} this
10785          */
10786         set : function(o, useSet){
10787             var el = this.dom;
10788             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
10789             for(var attr in o){
10790                 if(attr == "style" || typeof o[attr] == "function")  { continue; }
10791                 if(attr=="cls"){
10792                     el.className = o["cls"];
10793                 }else{
10794                     if(useSet) {
10795                         el.setAttribute(attr, o[attr]);
10796                     } else {
10797                         el[attr] = o[attr];
10798                     }
10799                 }
10800             }
10801             if(o.style){
10802                 Roo.DomHelper.applyStyles(el, o.style);
10803             }
10804             return this;
10805         },
10806
10807         /**
10808          * Convenience method for constructing a KeyMap
10809          * @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:
10810          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
10811          * @param {Function} fn The function to call
10812          * @param {Object} scope (optional) The scope of the function
10813          * @return {Roo.KeyMap} The KeyMap created
10814          */
10815         addKeyListener : function(key, fn, scope){
10816             var config;
10817             if(typeof key != "object" || key instanceof Array){
10818                 config = {
10819                     key: key,
10820                     fn: fn,
10821                     scope: scope
10822                 };
10823             }else{
10824                 config = {
10825                     key : key.key,
10826                     shift : key.shift,
10827                     ctrl : key.ctrl,
10828                     alt : key.alt,
10829                     fn: fn,
10830                     scope: scope
10831                 };
10832             }
10833             return new Roo.KeyMap(this, config);
10834         },
10835
10836         /**
10837          * Creates a KeyMap for this element
10838          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
10839          * @return {Roo.KeyMap} The KeyMap created
10840          */
10841         addKeyMap : function(config){
10842             return new Roo.KeyMap(this, config);
10843         },
10844
10845         /**
10846          * Returns true if this element is scrollable.
10847          * @return {Boolean}
10848          */
10849          isScrollable : function(){
10850             var dom = this.dom;
10851             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
10852         },
10853
10854         /**
10855          * 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().
10856          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
10857          * @param {Number} value The new scroll value
10858          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10859          * @return {Element} this
10860          */
10861
10862         scrollTo : function(side, value, animate){
10863             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
10864             if(!animate || !A){
10865                 this.dom[prop] = value;
10866             }else{
10867                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
10868                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
10869             }
10870             return this;
10871         },
10872
10873         /**
10874          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
10875          * within this element's scrollable range.
10876          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
10877          * @param {Number} distance How far to scroll the element in pixels
10878          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10879          * @return {Boolean} Returns true if a scroll was triggered or false if the element
10880          * was scrolled as far as it could go.
10881          */
10882          scroll : function(direction, distance, animate){
10883              if(!this.isScrollable()){
10884                  return;
10885              }
10886              var el = this.dom;
10887              var l = el.scrollLeft, t = el.scrollTop;
10888              var w = el.scrollWidth, h = el.scrollHeight;
10889              var cw = el.clientWidth, ch = el.clientHeight;
10890              direction = direction.toLowerCase();
10891              var scrolled = false;
10892              var a = this.preanim(arguments, 2);
10893              switch(direction){
10894                  case "l":
10895                  case "left":
10896                      if(w - l > cw){
10897                          var v = Math.min(l + distance, w-cw);
10898                          this.scrollTo("left", v, a);
10899                          scrolled = true;
10900                      }
10901                      break;
10902                 case "r":
10903                 case "right":
10904                      if(l > 0){
10905                          var v = Math.max(l - distance, 0);
10906                          this.scrollTo("left", v, a);
10907                          scrolled = true;
10908                      }
10909                      break;
10910                 case "t":
10911                 case "top":
10912                 case "up":
10913                      if(t > 0){
10914                          var v = Math.max(t - distance, 0);
10915                          this.scrollTo("top", v, a);
10916                          scrolled = true;
10917                      }
10918                      break;
10919                 case "b":
10920                 case "bottom":
10921                 case "down":
10922                      if(h - t > ch){
10923                          var v = Math.min(t + distance, h-ch);
10924                          this.scrollTo("top", v, a);
10925                          scrolled = true;
10926                      }
10927                      break;
10928              }
10929              return scrolled;
10930         },
10931
10932         /**
10933          * Translates the passed page coordinates into left/top css values for this element
10934          * @param {Number/Array} x The page x or an array containing [x, y]
10935          * @param {Number} y The page y
10936          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
10937          */
10938         translatePoints : function(x, y){
10939             if(typeof x == 'object' || x instanceof Array){
10940                 y = x[1]; x = x[0];
10941             }
10942             var p = this.getStyle('position');
10943             var o = this.getXY();
10944
10945             var l = parseInt(this.getStyle('left'), 10);
10946             var t = parseInt(this.getStyle('top'), 10);
10947
10948             if(isNaN(l)){
10949                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
10950             }
10951             if(isNaN(t)){
10952                 t = (p == "relative") ? 0 : this.dom.offsetTop;
10953             }
10954
10955             return {left: (x - o[0] + l), top: (y - o[1] + t)};
10956         },
10957
10958         /**
10959          * Returns the current scroll position of the element.
10960          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
10961          */
10962         getScroll : function(){
10963             var d = this.dom, doc = document;
10964             if(d == doc || d == doc.body){
10965                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
10966                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
10967                 return {left: l, top: t};
10968             }else{
10969                 return {left: d.scrollLeft, top: d.scrollTop};
10970             }
10971         },
10972
10973         /**
10974          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
10975          * are convert to standard 6 digit hex color.
10976          * @param {String} attr The css attribute
10977          * @param {String} defaultValue The default value to use when a valid color isn't found
10978          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
10979          * YUI color anims.
10980          */
10981         getColor : function(attr, defaultValue, prefix){
10982             var v = this.getStyle(attr);
10983             if(!v || v == "transparent" || v == "inherit") {
10984                 return defaultValue;
10985             }
10986             var color = typeof prefix == "undefined" ? "#" : prefix;
10987             if(v.substr(0, 4) == "rgb("){
10988                 var rvs = v.slice(4, v.length -1).split(",");
10989                 for(var i = 0; i < 3; i++){
10990                     var h = parseInt(rvs[i]).toString(16);
10991                     if(h < 16){
10992                         h = "0" + h;
10993                     }
10994                     color += h;
10995                 }
10996             } else {
10997                 if(v.substr(0, 1) == "#"){
10998                     if(v.length == 4) {
10999                         for(var i = 1; i < 4; i++){
11000                             var c = v.charAt(i);
11001                             color +=  c + c;
11002                         }
11003                     }else if(v.length == 7){
11004                         color += v.substr(1);
11005                     }
11006                 }
11007             }
11008             return(color.length > 5 ? color.toLowerCase() : defaultValue);
11009         },
11010
11011         /**
11012          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
11013          * gradient background, rounded corners and a 4-way shadow.
11014          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
11015          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
11016          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
11017          * @return {Roo.Element} this
11018          */
11019         boxWrap : function(cls){
11020             cls = cls || 'x-box';
11021             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
11022             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
11023             return el;
11024         },
11025
11026         /**
11027          * Returns the value of a namespaced attribute from the element's underlying DOM node.
11028          * @param {String} namespace The namespace in which to look for the attribute
11029          * @param {String} name The attribute name
11030          * @return {String} The attribute value
11031          */
11032         getAttributeNS : Roo.isIE ? function(ns, name){
11033             var d = this.dom;
11034             var type = typeof d[ns+":"+name];
11035             if(type != 'undefined' && type != 'unknown'){
11036                 return d[ns+":"+name];
11037             }
11038             return d[name];
11039         } : function(ns, name){
11040             var d = this.dom;
11041             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
11042         },
11043         
11044         
11045         /**
11046          * Sets or Returns the value the dom attribute value
11047          * @param {String|Object} name The attribute name (or object to set multiple attributes)
11048          * @param {String} value (optional) The value to set the attribute to
11049          * @return {String} The attribute value
11050          */
11051         attr : function(name){
11052             if (arguments.length > 1) {
11053                 this.dom.setAttribute(name, arguments[1]);
11054                 return arguments[1];
11055             }
11056             if (typeof(name) == 'object') {
11057                 for(var i in name) {
11058                     this.attr(i, name[i]);
11059                 }
11060                 return name;
11061             }
11062             
11063             
11064             if (!this.dom.hasAttribute(name)) {
11065                 return undefined;
11066             }
11067             return this.dom.getAttribute(name);
11068         }
11069         
11070         
11071         
11072     };
11073
11074     var ep = El.prototype;
11075
11076     /**
11077      * Appends an event handler (Shorthand for addListener)
11078      * @param {String}   eventName     The type of event to append
11079      * @param {Function} fn        The method the event invokes
11080      * @param {Object} scope       (optional) The scope (this object) of the fn
11081      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
11082      * @method
11083      */
11084     ep.on = ep.addListener;
11085         // backwards compat
11086     ep.mon = ep.addListener;
11087
11088     /**
11089      * Removes an event handler from this element (shorthand for removeListener)
11090      * @param {String} eventName the type of event to remove
11091      * @param {Function} fn the method the event invokes
11092      * @return {Roo.Element} this
11093      * @method
11094      */
11095     ep.un = ep.removeListener;
11096
11097     /**
11098      * true to automatically adjust width and height settings for box-model issues (default to true)
11099      */
11100     ep.autoBoxAdjust = true;
11101
11102     // private
11103     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
11104
11105     // private
11106     El.addUnits = function(v, defaultUnit){
11107         if(v === "" || v == "auto"){
11108             return v;
11109         }
11110         if(v === undefined){
11111             return '';
11112         }
11113         if(typeof v == "number" || !El.unitPattern.test(v)){
11114             return v + (defaultUnit || 'px');
11115         }
11116         return v;
11117     };
11118
11119     // special markup used throughout Roo when box wrapping elements
11120     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>';
11121     /**
11122      * Visibility mode constant - Use visibility to hide element
11123      * @static
11124      * @type Number
11125      */
11126     El.VISIBILITY = 1;
11127     /**
11128      * Visibility mode constant - Use display to hide element
11129      * @static
11130      * @type Number
11131      */
11132     El.DISPLAY = 2;
11133
11134     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
11135     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
11136     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
11137
11138
11139
11140     /**
11141      * @private
11142      */
11143     El.cache = {};
11144
11145     var docEl;
11146
11147     /**
11148      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
11149      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
11150      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
11151      * @return {Element} The Element object
11152      * @static
11153      */
11154     El.get = function(el){
11155         var ex, elm, id;
11156         if(!el){ return null; }
11157         if(typeof el == "string"){ // element id
11158             if(!(elm = document.getElementById(el))){
11159                 return null;
11160             }
11161             if(ex = El.cache[el]){
11162                 ex.dom = elm;
11163             }else{
11164                 ex = El.cache[el] = new El(elm);
11165             }
11166             return ex;
11167         }else if(el.tagName){ // dom element
11168             if(!(id = el.id)){
11169                 id = Roo.id(el);
11170             }
11171             if(ex = El.cache[id]){
11172                 ex.dom = el;
11173             }else{
11174                 ex = El.cache[id] = new El(el);
11175             }
11176             return ex;
11177         }else if(el instanceof El){
11178             if(el != docEl){
11179                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
11180                                                               // catch case where it hasn't been appended
11181                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
11182             }
11183             return el;
11184         }else if(el.isComposite){
11185             return el;
11186         }else if(el instanceof Array){
11187             return El.select(el);
11188         }else if(el == document){
11189             // create a bogus element object representing the document object
11190             if(!docEl){
11191                 var f = function(){};
11192                 f.prototype = El.prototype;
11193                 docEl = new f();
11194                 docEl.dom = document;
11195             }
11196             return docEl;
11197         }
11198         return null;
11199     };
11200
11201     // private
11202     El.uncache = function(el){
11203         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
11204             if(a[i]){
11205                 delete El.cache[a[i].id || a[i]];
11206             }
11207         }
11208     };
11209
11210     // private
11211     // Garbage collection - uncache elements/purge listeners on orphaned elements
11212     // so we don't hold a reference and cause the browser to retain them
11213     El.garbageCollect = function(){
11214         if(!Roo.enableGarbageCollector){
11215             clearInterval(El.collectorThread);
11216             return;
11217         }
11218         for(var eid in El.cache){
11219             var el = El.cache[eid], d = el.dom;
11220             // -------------------------------------------------------
11221             // Determining what is garbage:
11222             // -------------------------------------------------------
11223             // !d
11224             // dom node is null, definitely garbage
11225             // -------------------------------------------------------
11226             // !d.parentNode
11227             // no parentNode == direct orphan, definitely garbage
11228             // -------------------------------------------------------
11229             // !d.offsetParent && !document.getElementById(eid)
11230             // display none elements have no offsetParent so we will
11231             // also try to look it up by it's id. However, check
11232             // offsetParent first so we don't do unneeded lookups.
11233             // This enables collection of elements that are not orphans
11234             // directly, but somewhere up the line they have an orphan
11235             // parent.
11236             // -------------------------------------------------------
11237             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
11238                 delete El.cache[eid];
11239                 if(d && Roo.enableListenerCollection){
11240                     E.purgeElement(d);
11241                 }
11242             }
11243         }
11244     }
11245     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
11246
11247
11248     // dom is optional
11249     El.Flyweight = function(dom){
11250         this.dom = dom;
11251     };
11252     El.Flyweight.prototype = El.prototype;
11253
11254     El._flyweights = {};
11255     /**
11256      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
11257      * the dom node can be overwritten by other code.
11258      * @param {String/HTMLElement} el The dom node or id
11259      * @param {String} named (optional) Allows for creation of named reusable flyweights to
11260      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
11261      * @static
11262      * @return {Element} The shared Element object
11263      */
11264     El.fly = function(el, named){
11265         named = named || '_global';
11266         el = Roo.getDom(el);
11267         if(!el){
11268             return null;
11269         }
11270         if(!El._flyweights[named]){
11271             El._flyweights[named] = new El.Flyweight();
11272         }
11273         El._flyweights[named].dom = el;
11274         return El._flyweights[named];
11275     };
11276
11277     /**
11278      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
11279      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
11280      * Shorthand of {@link Roo.Element#get}
11281      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
11282      * @return {Element} The Element object
11283      * @member Roo
11284      * @method get
11285      */
11286     Roo.get = El.get;
11287     /**
11288      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
11289      * the dom node can be overwritten by other code.
11290      * Shorthand of {@link Roo.Element#fly}
11291      * @param {String/HTMLElement} el The dom node or id
11292      * @param {String} named (optional) Allows for creation of named reusable flyweights to
11293      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
11294      * @static
11295      * @return {Element} The shared Element object
11296      * @member Roo
11297      * @method fly
11298      */
11299     Roo.fly = El.fly;
11300
11301     // speedy lookup for elements never to box adjust
11302     var noBoxAdjust = Roo.isStrict ? {
11303         select:1
11304     } : {
11305         input:1, select:1, textarea:1
11306     };
11307     if(Roo.isIE || Roo.isGecko){
11308         noBoxAdjust['button'] = 1;
11309     }
11310
11311
11312     Roo.EventManager.on(window, 'unload', function(){
11313         delete El.cache;
11314         delete El._flyweights;
11315     });
11316 })();
11317
11318
11319
11320
11321 if(Roo.DomQuery){
11322     Roo.Element.selectorFunction = Roo.DomQuery.select;
11323 }
11324
11325 Roo.Element.select = function(selector, unique, root){
11326     var els;
11327     if(typeof selector == "string"){
11328         els = Roo.Element.selectorFunction(selector, root);
11329     }else if(selector.length !== undefined){
11330         els = selector;
11331     }else{
11332         throw "Invalid selector";
11333     }
11334     if(unique === true){
11335         return new Roo.CompositeElement(els);
11336     }else{
11337         return new Roo.CompositeElementLite(els);
11338     }
11339 };
11340 /**
11341  * Selects elements based on the passed CSS selector to enable working on them as 1.
11342  * @param {String/Array} selector The CSS selector or an array of elements
11343  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
11344  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
11345  * @return {CompositeElementLite/CompositeElement}
11346  * @member Roo
11347  * @method select
11348  */
11349 Roo.select = Roo.Element.select;
11350
11351
11352
11353
11354
11355
11356
11357
11358
11359
11360
11361
11362
11363
11364 /*
11365  * Based on:
11366  * Ext JS Library 1.1.1
11367  * Copyright(c) 2006-2007, Ext JS, LLC.
11368  *
11369  * Originally Released Under LGPL - original licence link has changed is not relivant.
11370  *
11371  * Fork - LGPL
11372  * <script type="text/javascript">
11373  */
11374
11375
11376
11377 //Notifies Element that fx methods are available
11378 Roo.enableFx = true;
11379
11380 /**
11381  * @class Roo.Fx
11382  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
11383  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
11384  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
11385  * Element effects to work.</p><br/>
11386  *
11387  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
11388  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
11389  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
11390  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
11391  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
11392  * expected results and should be done with care.</p><br/>
11393  *
11394  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
11395  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
11396 <pre>
11397 Value  Description
11398 -----  -----------------------------
11399 tl     The top left corner
11400 t      The center of the top edge
11401 tr     The top right corner
11402 l      The center of the left edge
11403 r      The center of the right edge
11404 bl     The bottom left corner
11405 b      The center of the bottom edge
11406 br     The bottom right corner
11407 </pre>
11408  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
11409  * below are common options that can be passed to any Fx method.</b>
11410  * @cfg {Function} callback A function called when the effect is finished
11411  * @cfg {Object} scope The scope of the effect function
11412  * @cfg {String} easing A valid Easing value for the effect
11413  * @cfg {String} afterCls A css class to apply after the effect
11414  * @cfg {Number} duration The length of time (in seconds) that the effect should last
11415  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
11416  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
11417  * effects that end with the element being visually hidden, ignored otherwise)
11418  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
11419  * a function which returns such a specification that will be applied to the Element after the effect finishes
11420  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
11421  * @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
11422  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
11423  */
11424 Roo.Fx = {
11425         /**
11426          * Slides the element into view.  An anchor point can be optionally passed to set the point of
11427          * origin for the slide effect.  This function automatically handles wrapping the element with
11428          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
11429          * Usage:
11430          *<pre><code>
11431 // default: slide the element in from the top
11432 el.slideIn();
11433
11434 // custom: slide the element in from the right with a 2-second duration
11435 el.slideIn('r', { duration: 2 });
11436
11437 // common config options shown with default values
11438 el.slideIn('t', {
11439     easing: 'easeOut',
11440     duration: .5
11441 });
11442 </code></pre>
11443          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
11444          * @param {Object} options (optional) Object literal with any of the Fx config options
11445          * @return {Roo.Element} The Element
11446          */
11447     slideIn : function(anchor, o){
11448         var el = this.getFxEl();
11449         o = o || {};
11450
11451         el.queueFx(o, function(){
11452
11453             anchor = anchor || "t";
11454
11455             // fix display to visibility
11456             this.fixDisplay();
11457
11458             // restore values after effect
11459             var r = this.getFxRestore();
11460             var b = this.getBox();
11461             // fixed size for slide
11462             this.setSize(b);
11463
11464             // wrap if needed
11465             var wrap = this.fxWrap(r.pos, o, "hidden");
11466
11467             var st = this.dom.style;
11468             st.visibility = "visible";
11469             st.position = "absolute";
11470
11471             // clear out temp styles after slide and unwrap
11472             var after = function(){
11473                 el.fxUnwrap(wrap, r.pos, o);
11474                 st.width = r.width;
11475                 st.height = r.height;
11476                 el.afterFx(o);
11477             };
11478             // time to calc the positions
11479             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
11480
11481             switch(anchor.toLowerCase()){
11482                 case "t":
11483                     wrap.setSize(b.width, 0);
11484                     st.left = st.bottom = "0";
11485                     a = {height: bh};
11486                 break;
11487                 case "l":
11488                     wrap.setSize(0, b.height);
11489                     st.right = st.top = "0";
11490                     a = {width: bw};
11491                 break;
11492                 case "r":
11493                     wrap.setSize(0, b.height);
11494                     wrap.setX(b.right);
11495                     st.left = st.top = "0";
11496                     a = {width: bw, points: pt};
11497                 break;
11498                 case "b":
11499                     wrap.setSize(b.width, 0);
11500                     wrap.setY(b.bottom);
11501                     st.left = st.top = "0";
11502                     a = {height: bh, points: pt};
11503                 break;
11504                 case "tl":
11505                     wrap.setSize(0, 0);
11506                     st.right = st.bottom = "0";
11507                     a = {width: bw, height: bh};
11508                 break;
11509                 case "bl":
11510                     wrap.setSize(0, 0);
11511                     wrap.setY(b.y+b.height);
11512                     st.right = st.top = "0";
11513                     a = {width: bw, height: bh, points: pt};
11514                 break;
11515                 case "br":
11516                     wrap.setSize(0, 0);
11517                     wrap.setXY([b.right, b.bottom]);
11518                     st.left = st.top = "0";
11519                     a = {width: bw, height: bh, points: pt};
11520                 break;
11521                 case "tr":
11522                     wrap.setSize(0, 0);
11523                     wrap.setX(b.x+b.width);
11524                     st.left = st.bottom = "0";
11525                     a = {width: bw, height: bh, points: pt};
11526                 break;
11527             }
11528             this.dom.style.visibility = "visible";
11529             wrap.show();
11530
11531             arguments.callee.anim = wrap.fxanim(a,
11532                 o,
11533                 'motion',
11534                 .5,
11535                 'easeOut', after);
11536         });
11537         return this;
11538     },
11539     
11540         /**
11541          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
11542          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
11543          * 'hidden') but block elements will still take up space in the document.  The element must be removed
11544          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
11545          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
11546          * Usage:
11547          *<pre><code>
11548 // default: slide the element out to the top
11549 el.slideOut();
11550
11551 // custom: slide the element out to the right with a 2-second duration
11552 el.slideOut('r', { duration: 2 });
11553
11554 // common config options shown with default values
11555 el.slideOut('t', {
11556     easing: 'easeOut',
11557     duration: .5,
11558     remove: false,
11559     useDisplay: false
11560 });
11561 </code></pre>
11562          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
11563          * @param {Object} options (optional) Object literal with any of the Fx config options
11564          * @return {Roo.Element} The Element
11565          */
11566     slideOut : function(anchor, o){
11567         var el = this.getFxEl();
11568         o = o || {};
11569
11570         el.queueFx(o, function(){
11571
11572             anchor = anchor || "t";
11573
11574             // restore values after effect
11575             var r = this.getFxRestore();
11576             
11577             var b = this.getBox();
11578             // fixed size for slide
11579             this.setSize(b);
11580
11581             // wrap if needed
11582             var wrap = this.fxWrap(r.pos, o, "visible");
11583
11584             var st = this.dom.style;
11585             st.visibility = "visible";
11586             st.position = "absolute";
11587
11588             wrap.setSize(b);
11589
11590             var after = function(){
11591                 if(o.useDisplay){
11592                     el.setDisplayed(false);
11593                 }else{
11594                     el.hide();
11595                 }
11596
11597                 el.fxUnwrap(wrap, r.pos, o);
11598
11599                 st.width = r.width;
11600                 st.height = r.height;
11601
11602                 el.afterFx(o);
11603             };
11604
11605             var a, zero = {to: 0};
11606             switch(anchor.toLowerCase()){
11607                 case "t":
11608                     st.left = st.bottom = "0";
11609                     a = {height: zero};
11610                 break;
11611                 case "l":
11612                     st.right = st.top = "0";
11613                     a = {width: zero};
11614                 break;
11615                 case "r":
11616                     st.left = st.top = "0";
11617                     a = {width: zero, points: {to:[b.right, b.y]}};
11618                 break;
11619                 case "b":
11620                     st.left = st.top = "0";
11621                     a = {height: zero, points: {to:[b.x, b.bottom]}};
11622                 break;
11623                 case "tl":
11624                     st.right = st.bottom = "0";
11625                     a = {width: zero, height: zero};
11626                 break;
11627                 case "bl":
11628                     st.right = st.top = "0";
11629                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
11630                 break;
11631                 case "br":
11632                     st.left = st.top = "0";
11633                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
11634                 break;
11635                 case "tr":
11636                     st.left = st.bottom = "0";
11637                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
11638                 break;
11639             }
11640
11641             arguments.callee.anim = wrap.fxanim(a,
11642                 o,
11643                 'motion',
11644                 .5,
11645                 "easeOut", after);
11646         });
11647         return this;
11648     },
11649
11650         /**
11651          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
11652          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
11653          * The element must be removed from the DOM using the 'remove' config option if desired.
11654          * Usage:
11655          *<pre><code>
11656 // default
11657 el.puff();
11658
11659 // common config options shown with default values
11660 el.puff({
11661     easing: 'easeOut',
11662     duration: .5,
11663     remove: false,
11664     useDisplay: false
11665 });
11666 </code></pre>
11667          * @param {Object} options (optional) Object literal with any of the Fx config options
11668          * @return {Roo.Element} The Element
11669          */
11670     puff : function(o){
11671         var el = this.getFxEl();
11672         o = o || {};
11673
11674         el.queueFx(o, function(){
11675             this.clearOpacity();
11676             this.show();
11677
11678             // restore values after effect
11679             var r = this.getFxRestore();
11680             var st = this.dom.style;
11681
11682             var after = function(){
11683                 if(o.useDisplay){
11684                     el.setDisplayed(false);
11685                 }else{
11686                     el.hide();
11687                 }
11688
11689                 el.clearOpacity();
11690
11691                 el.setPositioning(r.pos);
11692                 st.width = r.width;
11693                 st.height = r.height;
11694                 st.fontSize = '';
11695                 el.afterFx(o);
11696             };
11697
11698             var width = this.getWidth();
11699             var height = this.getHeight();
11700
11701             arguments.callee.anim = this.fxanim({
11702                     width : {to: this.adjustWidth(width * 2)},
11703                     height : {to: this.adjustHeight(height * 2)},
11704                     points : {by: [-(width * .5), -(height * .5)]},
11705                     opacity : {to: 0},
11706                     fontSize: {to:200, unit: "%"}
11707                 },
11708                 o,
11709                 'motion',
11710                 .5,
11711                 "easeOut", after);
11712         });
11713         return this;
11714     },
11715
11716         /**
11717          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
11718          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
11719          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
11720          * Usage:
11721          *<pre><code>
11722 // default
11723 el.switchOff();
11724
11725 // all config options shown with default values
11726 el.switchOff({
11727     easing: 'easeIn',
11728     duration: .3,
11729     remove: false,
11730     useDisplay: false
11731 });
11732 </code></pre>
11733          * @param {Object} options (optional) Object literal with any of the Fx config options
11734          * @return {Roo.Element} The Element
11735          */
11736     switchOff : function(o){
11737         var el = this.getFxEl();
11738         o = o || {};
11739
11740         el.queueFx(o, function(){
11741             this.clearOpacity();
11742             this.clip();
11743
11744             // restore values after effect
11745             var r = this.getFxRestore();
11746             var st = this.dom.style;
11747
11748             var after = function(){
11749                 if(o.useDisplay){
11750                     el.setDisplayed(false);
11751                 }else{
11752                     el.hide();
11753                 }
11754
11755                 el.clearOpacity();
11756                 el.setPositioning(r.pos);
11757                 st.width = r.width;
11758                 st.height = r.height;
11759
11760                 el.afterFx(o);
11761             };
11762
11763             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
11764                 this.clearOpacity();
11765                 (function(){
11766                     this.fxanim({
11767                         height:{to:1},
11768                         points:{by:[0, this.getHeight() * .5]}
11769                     }, o, 'motion', 0.3, 'easeIn', after);
11770                 }).defer(100, this);
11771             });
11772         });
11773         return this;
11774     },
11775
11776     /**
11777      * Highlights the Element by setting a color (applies to the background-color by default, but can be
11778      * changed using the "attr" config option) and then fading back to the original color. If no original
11779      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
11780      * Usage:
11781 <pre><code>
11782 // default: highlight background to yellow
11783 el.highlight();
11784
11785 // custom: highlight foreground text to blue for 2 seconds
11786 el.highlight("0000ff", { attr: 'color', duration: 2 });
11787
11788 // common config options shown with default values
11789 el.highlight("ffff9c", {
11790     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
11791     endColor: (current color) or "ffffff",
11792     easing: 'easeIn',
11793     duration: 1
11794 });
11795 </code></pre>
11796      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
11797      * @param {Object} options (optional) Object literal with any of the Fx config options
11798      * @return {Roo.Element} The Element
11799      */ 
11800     highlight : function(color, o){
11801         var el = this.getFxEl();
11802         o = o || {};
11803
11804         el.queueFx(o, function(){
11805             color = color || "ffff9c";
11806             attr = o.attr || "backgroundColor";
11807
11808             this.clearOpacity();
11809             this.show();
11810
11811             var origColor = this.getColor(attr);
11812             var restoreColor = this.dom.style[attr];
11813             endColor = (o.endColor || origColor) || "ffffff";
11814
11815             var after = function(){
11816                 el.dom.style[attr] = restoreColor;
11817                 el.afterFx(o);
11818             };
11819
11820             var a = {};
11821             a[attr] = {from: color, to: endColor};
11822             arguments.callee.anim = this.fxanim(a,
11823                 o,
11824                 'color',
11825                 1,
11826                 'easeIn', after);
11827         });
11828         return this;
11829     },
11830
11831    /**
11832     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
11833     * Usage:
11834 <pre><code>
11835 // default: a single light blue ripple
11836 el.frame();
11837
11838 // custom: 3 red ripples lasting 3 seconds total
11839 el.frame("ff0000", 3, { duration: 3 });
11840
11841 // common config options shown with default values
11842 el.frame("C3DAF9", 1, {
11843     duration: 1 //duration of entire animation (not each individual ripple)
11844     // Note: Easing is not configurable and will be ignored if included
11845 });
11846 </code></pre>
11847     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
11848     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
11849     * @param {Object} options (optional) Object literal with any of the Fx config options
11850     * @return {Roo.Element} The Element
11851     */
11852     frame : function(color, count, o){
11853         var el = this.getFxEl();
11854         o = o || {};
11855
11856         el.queueFx(o, function(){
11857             color = color || "#C3DAF9";
11858             if(color.length == 6){
11859                 color = "#" + color;
11860             }
11861             count = count || 1;
11862             duration = o.duration || 1;
11863             this.show();
11864
11865             var b = this.getBox();
11866             var animFn = function(){
11867                 var proxy = this.createProxy({
11868
11869                      style:{
11870                         visbility:"hidden",
11871                         position:"absolute",
11872                         "z-index":"35000", // yee haw
11873                         border:"0px solid " + color
11874                      }
11875                   });
11876                 var scale = Roo.isBorderBox ? 2 : 1;
11877                 proxy.animate({
11878                     top:{from:b.y, to:b.y - 20},
11879                     left:{from:b.x, to:b.x - 20},
11880                     borderWidth:{from:0, to:10},
11881                     opacity:{from:1, to:0},
11882                     height:{from:b.height, to:(b.height + (20*scale))},
11883                     width:{from:b.width, to:(b.width + (20*scale))}
11884                 }, duration, function(){
11885                     proxy.remove();
11886                 });
11887                 if(--count > 0){
11888                      animFn.defer((duration/2)*1000, this);
11889                 }else{
11890                     el.afterFx(o);
11891                 }
11892             };
11893             animFn.call(this);
11894         });
11895         return this;
11896     },
11897
11898    /**
11899     * Creates a pause before any subsequent queued effects begin.  If there are
11900     * no effects queued after the pause it will have no effect.
11901     * Usage:
11902 <pre><code>
11903 el.pause(1);
11904 </code></pre>
11905     * @param {Number} seconds The length of time to pause (in seconds)
11906     * @return {Roo.Element} The Element
11907     */
11908     pause : function(seconds){
11909         var el = this.getFxEl();
11910         var o = {};
11911
11912         el.queueFx(o, function(){
11913             setTimeout(function(){
11914                 el.afterFx(o);
11915             }, seconds * 1000);
11916         });
11917         return this;
11918     },
11919
11920    /**
11921     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
11922     * using the "endOpacity" config option.
11923     * Usage:
11924 <pre><code>
11925 // default: fade in from opacity 0 to 100%
11926 el.fadeIn();
11927
11928 // custom: fade in from opacity 0 to 75% over 2 seconds
11929 el.fadeIn({ endOpacity: .75, duration: 2});
11930
11931 // common config options shown with default values
11932 el.fadeIn({
11933     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
11934     easing: 'easeOut',
11935     duration: .5
11936 });
11937 </code></pre>
11938     * @param {Object} options (optional) Object literal with any of the Fx config options
11939     * @return {Roo.Element} The Element
11940     */
11941     fadeIn : function(o){
11942         var el = this.getFxEl();
11943         o = o || {};
11944         el.queueFx(o, function(){
11945             this.setOpacity(0);
11946             this.fixDisplay();
11947             this.dom.style.visibility = 'visible';
11948             var to = o.endOpacity || 1;
11949             arguments.callee.anim = this.fxanim({opacity:{to:to}},
11950                 o, null, .5, "easeOut", function(){
11951                 if(to == 1){
11952                     this.clearOpacity();
11953                 }
11954                 el.afterFx(o);
11955             });
11956         });
11957         return this;
11958     },
11959
11960    /**
11961     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
11962     * using the "endOpacity" config option.
11963     * Usage:
11964 <pre><code>
11965 // default: fade out from the element's current opacity to 0
11966 el.fadeOut();
11967
11968 // custom: fade out from the element's current opacity to 25% over 2 seconds
11969 el.fadeOut({ endOpacity: .25, duration: 2});
11970
11971 // common config options shown with default values
11972 el.fadeOut({
11973     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
11974     easing: 'easeOut',
11975     duration: .5
11976     remove: false,
11977     useDisplay: false
11978 });
11979 </code></pre>
11980     * @param {Object} options (optional) Object literal with any of the Fx config options
11981     * @return {Roo.Element} The Element
11982     */
11983     fadeOut : function(o){
11984         var el = this.getFxEl();
11985         o = o || {};
11986         el.queueFx(o, function(){
11987             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
11988                 o, null, .5, "easeOut", function(){
11989                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
11990                      this.dom.style.display = "none";
11991                 }else{
11992                      this.dom.style.visibility = "hidden";
11993                 }
11994                 this.clearOpacity();
11995                 el.afterFx(o);
11996             });
11997         });
11998         return this;
11999     },
12000
12001    /**
12002     * Animates the transition of an element's dimensions from a starting height/width
12003     * to an ending height/width.
12004     * Usage:
12005 <pre><code>
12006 // change height and width to 100x100 pixels
12007 el.scale(100, 100);
12008
12009 // common config options shown with default values.  The height and width will default to
12010 // the element's existing values if passed as null.
12011 el.scale(
12012     [element's width],
12013     [element's height], {
12014     easing: 'easeOut',
12015     duration: .35
12016 });
12017 </code></pre>
12018     * @param {Number} width  The new width (pass undefined to keep the original width)
12019     * @param {Number} height  The new height (pass undefined to keep the original height)
12020     * @param {Object} options (optional) Object literal with any of the Fx config options
12021     * @return {Roo.Element} The Element
12022     */
12023     scale : function(w, h, o){
12024         this.shift(Roo.apply({}, o, {
12025             width: w,
12026             height: h
12027         }));
12028         return this;
12029     },
12030
12031    /**
12032     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
12033     * Any of these properties not specified in the config object will not be changed.  This effect 
12034     * requires that at least one new dimension, position or opacity setting must be passed in on
12035     * the config object in order for the function to have any effect.
12036     * Usage:
12037 <pre><code>
12038 // slide the element horizontally to x position 200 while changing the height and opacity
12039 el.shift({ x: 200, height: 50, opacity: .8 });
12040
12041 // common config options shown with default values.
12042 el.shift({
12043     width: [element's width],
12044     height: [element's height],
12045     x: [element's x position],
12046     y: [element's y position],
12047     opacity: [element's opacity],
12048     easing: 'easeOut',
12049     duration: .35
12050 });
12051 </code></pre>
12052     * @param {Object} options  Object literal with any of the Fx config options
12053     * @return {Roo.Element} The Element
12054     */
12055     shift : function(o){
12056         var el = this.getFxEl();
12057         o = o || {};
12058         el.queueFx(o, function(){
12059             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
12060             if(w !== undefined){
12061                 a.width = {to: this.adjustWidth(w)};
12062             }
12063             if(h !== undefined){
12064                 a.height = {to: this.adjustHeight(h)};
12065             }
12066             if(x !== undefined || y !== undefined){
12067                 a.points = {to: [
12068                     x !== undefined ? x : this.getX(),
12069                     y !== undefined ? y : this.getY()
12070                 ]};
12071             }
12072             if(op !== undefined){
12073                 a.opacity = {to: op};
12074             }
12075             if(o.xy !== undefined){
12076                 a.points = {to: o.xy};
12077             }
12078             arguments.callee.anim = this.fxanim(a,
12079                 o, 'motion', .35, "easeOut", function(){
12080                 el.afterFx(o);
12081             });
12082         });
12083         return this;
12084     },
12085
12086         /**
12087          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
12088          * ending point of the effect.
12089          * Usage:
12090          *<pre><code>
12091 // default: slide the element downward while fading out
12092 el.ghost();
12093
12094 // custom: slide the element out to the right with a 2-second duration
12095 el.ghost('r', { duration: 2 });
12096
12097 // common config options shown with default values
12098 el.ghost('b', {
12099     easing: 'easeOut',
12100     duration: .5
12101     remove: false,
12102     useDisplay: false
12103 });
12104 </code></pre>
12105          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
12106          * @param {Object} options (optional) Object literal with any of the Fx config options
12107          * @return {Roo.Element} The Element
12108          */
12109     ghost : function(anchor, o){
12110         var el = this.getFxEl();
12111         o = o || {};
12112
12113         el.queueFx(o, function(){
12114             anchor = anchor || "b";
12115
12116             // restore values after effect
12117             var r = this.getFxRestore();
12118             var w = this.getWidth(),
12119                 h = this.getHeight();
12120
12121             var st = this.dom.style;
12122
12123             var after = function(){
12124                 if(o.useDisplay){
12125                     el.setDisplayed(false);
12126                 }else{
12127                     el.hide();
12128                 }
12129
12130                 el.clearOpacity();
12131                 el.setPositioning(r.pos);
12132                 st.width = r.width;
12133                 st.height = r.height;
12134
12135                 el.afterFx(o);
12136             };
12137
12138             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
12139             switch(anchor.toLowerCase()){
12140                 case "t":
12141                     pt.by = [0, -h];
12142                 break;
12143                 case "l":
12144                     pt.by = [-w, 0];
12145                 break;
12146                 case "r":
12147                     pt.by = [w, 0];
12148                 break;
12149                 case "b":
12150                     pt.by = [0, h];
12151                 break;
12152                 case "tl":
12153                     pt.by = [-w, -h];
12154                 break;
12155                 case "bl":
12156                     pt.by = [-w, h];
12157                 break;
12158                 case "br":
12159                     pt.by = [w, h];
12160                 break;
12161                 case "tr":
12162                     pt.by = [w, -h];
12163                 break;
12164             }
12165
12166             arguments.callee.anim = this.fxanim(a,
12167                 o,
12168                 'motion',
12169                 .5,
12170                 "easeOut", after);
12171         });
12172         return this;
12173     },
12174
12175         /**
12176          * Ensures that all effects queued after syncFx is called on the element are
12177          * run concurrently.  This is the opposite of {@link #sequenceFx}.
12178          * @return {Roo.Element} The Element
12179          */
12180     syncFx : function(){
12181         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
12182             block : false,
12183             concurrent : true,
12184             stopFx : false
12185         });
12186         return this;
12187     },
12188
12189         /**
12190          * Ensures that all effects queued after sequenceFx is called on the element are
12191          * run in sequence.  This is the opposite of {@link #syncFx}.
12192          * @return {Roo.Element} The Element
12193          */
12194     sequenceFx : function(){
12195         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
12196             block : false,
12197             concurrent : false,
12198             stopFx : false
12199         });
12200         return this;
12201     },
12202
12203         /* @private */
12204     nextFx : function(){
12205         var ef = this.fxQueue[0];
12206         if(ef){
12207             ef.call(this);
12208         }
12209     },
12210
12211         /**
12212          * Returns true if the element has any effects actively running or queued, else returns false.
12213          * @return {Boolean} True if element has active effects, else false
12214          */
12215     hasActiveFx : function(){
12216         return this.fxQueue && this.fxQueue[0];
12217     },
12218
12219         /**
12220          * Stops any running effects and clears the element's internal effects queue if it contains
12221          * any additional effects that haven't started yet.
12222          * @return {Roo.Element} The Element
12223          */
12224     stopFx : function(){
12225         if(this.hasActiveFx()){
12226             var cur = this.fxQueue[0];
12227             if(cur && cur.anim && cur.anim.isAnimated()){
12228                 this.fxQueue = [cur]; // clear out others
12229                 cur.anim.stop(true);
12230             }
12231         }
12232         return this;
12233     },
12234
12235         /* @private */
12236     beforeFx : function(o){
12237         if(this.hasActiveFx() && !o.concurrent){
12238            if(o.stopFx){
12239                this.stopFx();
12240                return true;
12241            }
12242            return false;
12243         }
12244         return true;
12245     },
12246
12247         /**
12248          * Returns true if the element is currently blocking so that no other effect can be queued
12249          * until this effect is finished, else returns false if blocking is not set.  This is commonly
12250          * used to ensure that an effect initiated by a user action runs to completion prior to the
12251          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
12252          * @return {Boolean} True if blocking, else false
12253          */
12254     hasFxBlock : function(){
12255         var q = this.fxQueue;
12256         return q && q[0] && q[0].block;
12257     },
12258
12259         /* @private */
12260     queueFx : function(o, fn){
12261         if(!this.fxQueue){
12262             this.fxQueue = [];
12263         }
12264         if(!this.hasFxBlock()){
12265             Roo.applyIf(o, this.fxDefaults);
12266             if(!o.concurrent){
12267                 var run = this.beforeFx(o);
12268                 fn.block = o.block;
12269                 this.fxQueue.push(fn);
12270                 if(run){
12271                     this.nextFx();
12272                 }
12273             }else{
12274                 fn.call(this);
12275             }
12276         }
12277         return this;
12278     },
12279
12280         /* @private */
12281     fxWrap : function(pos, o, vis){
12282         var wrap;
12283         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
12284             var wrapXY;
12285             if(o.fixPosition){
12286                 wrapXY = this.getXY();
12287             }
12288             var div = document.createElement("div");
12289             div.style.visibility = vis;
12290             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
12291             wrap.setPositioning(pos);
12292             if(wrap.getStyle("position") == "static"){
12293                 wrap.position("relative");
12294             }
12295             this.clearPositioning('auto');
12296             wrap.clip();
12297             wrap.dom.appendChild(this.dom);
12298             if(wrapXY){
12299                 wrap.setXY(wrapXY);
12300             }
12301         }
12302         return wrap;
12303     },
12304
12305         /* @private */
12306     fxUnwrap : function(wrap, pos, o){
12307         this.clearPositioning();
12308         this.setPositioning(pos);
12309         if(!o.wrap){
12310             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
12311             wrap.remove();
12312         }
12313     },
12314
12315         /* @private */
12316     getFxRestore : function(){
12317         var st = this.dom.style;
12318         return {pos: this.getPositioning(), width: st.width, height : st.height};
12319     },
12320
12321         /* @private */
12322     afterFx : function(o){
12323         if(o.afterStyle){
12324             this.applyStyles(o.afterStyle);
12325         }
12326         if(o.afterCls){
12327             this.addClass(o.afterCls);
12328         }
12329         if(o.remove === true){
12330             this.remove();
12331         }
12332         Roo.callback(o.callback, o.scope, [this]);
12333         if(!o.concurrent){
12334             this.fxQueue.shift();
12335             this.nextFx();
12336         }
12337     },
12338
12339         /* @private */
12340     getFxEl : function(){ // support for composite element fx
12341         return Roo.get(this.dom);
12342     },
12343
12344         /* @private */
12345     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
12346         animType = animType || 'run';
12347         opt = opt || {};
12348         var anim = Roo.lib.Anim[animType](
12349             this.dom, args,
12350             (opt.duration || defaultDur) || .35,
12351             (opt.easing || defaultEase) || 'easeOut',
12352             function(){
12353                 Roo.callback(cb, this);
12354             },
12355             this
12356         );
12357         opt.anim = anim;
12358         return anim;
12359     }
12360 };
12361
12362 // backwords compat
12363 Roo.Fx.resize = Roo.Fx.scale;
12364
12365 //When included, Roo.Fx is automatically applied to Element so that all basic
12366 //effects are available directly via the Element API
12367 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
12368  * Based on:
12369  * Ext JS Library 1.1.1
12370  * Copyright(c) 2006-2007, Ext JS, LLC.
12371  *
12372  * Originally Released Under LGPL - original licence link has changed is not relivant.
12373  *
12374  * Fork - LGPL
12375  * <script type="text/javascript">
12376  */
12377
12378
12379 /**
12380  * @class Roo.CompositeElement
12381  * Standard composite class. Creates a Roo.Element for every element in the collection.
12382  * <br><br>
12383  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
12384  * actions will be performed on all the elements in this collection.</b>
12385  * <br><br>
12386  * All methods return <i>this</i> and can be chained.
12387  <pre><code>
12388  var els = Roo.select("#some-el div.some-class", true);
12389  // or select directly from an existing element
12390  var el = Roo.get('some-el');
12391  el.select('div.some-class', true);
12392
12393  els.setWidth(100); // all elements become 100 width
12394  els.hide(true); // all elements fade out and hide
12395  // or
12396  els.setWidth(100).hide(true);
12397  </code></pre>
12398  */
12399 Roo.CompositeElement = function(els){
12400     this.elements = [];
12401     this.addElements(els);
12402 };
12403 Roo.CompositeElement.prototype = {
12404     isComposite: true,
12405     addElements : function(els){
12406         if(!els) {
12407             return this;
12408         }
12409         if(typeof els == "string"){
12410             els = Roo.Element.selectorFunction(els);
12411         }
12412         var yels = this.elements;
12413         var index = yels.length-1;
12414         for(var i = 0, len = els.length; i < len; i++) {
12415                 yels[++index] = Roo.get(els[i]);
12416         }
12417         return this;
12418     },
12419
12420     /**
12421     * Clears this composite and adds the elements returned by the passed selector.
12422     * @param {String/Array} els A string CSS selector, an array of elements or an element
12423     * @return {CompositeElement} this
12424     */
12425     fill : function(els){
12426         this.elements = [];
12427         this.add(els);
12428         return this;
12429     },
12430
12431     /**
12432     * Filters this composite to only elements that match the passed selector.
12433     * @param {String} selector A string CSS selector
12434     * @param {Boolean} inverse return inverse filter (not matches)
12435     * @return {CompositeElement} this
12436     */
12437     filter : function(selector, inverse){
12438         var els = [];
12439         inverse = inverse || false;
12440         this.each(function(el){
12441             var match = inverse ? !el.is(selector) : el.is(selector);
12442             if(match){
12443                 els[els.length] = el.dom;
12444             }
12445         });
12446         this.fill(els);
12447         return this;
12448     },
12449
12450     invoke : function(fn, args){
12451         var els = this.elements;
12452         for(var i = 0, len = els.length; i < len; i++) {
12453                 Roo.Element.prototype[fn].apply(els[i], args);
12454         }
12455         return this;
12456     },
12457     /**
12458     * Adds elements to this composite.
12459     * @param {String/Array} els A string CSS selector, an array of elements or an element
12460     * @return {CompositeElement} this
12461     */
12462     add : function(els){
12463         if(typeof els == "string"){
12464             this.addElements(Roo.Element.selectorFunction(els));
12465         }else if(els.length !== undefined){
12466             this.addElements(els);
12467         }else{
12468             this.addElements([els]);
12469         }
12470         return this;
12471     },
12472     /**
12473     * Calls the passed function passing (el, this, index) for each element in this composite.
12474     * @param {Function} fn The function to call
12475     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
12476     * @return {CompositeElement} this
12477     */
12478     each : function(fn, scope){
12479         var els = this.elements;
12480         for(var i = 0, len = els.length; i < len; i++){
12481             if(fn.call(scope || els[i], els[i], this, i) === false) {
12482                 break;
12483             }
12484         }
12485         return this;
12486     },
12487
12488     /**
12489      * Returns the Element object at the specified index
12490      * @param {Number} index
12491      * @return {Roo.Element}
12492      */
12493     item : function(index){
12494         return this.elements[index] || null;
12495     },
12496
12497     /**
12498      * Returns the first Element
12499      * @return {Roo.Element}
12500      */
12501     first : function(){
12502         return this.item(0);
12503     },
12504
12505     /**
12506      * Returns the last Element
12507      * @return {Roo.Element}
12508      */
12509     last : function(){
12510         return this.item(this.elements.length-1);
12511     },
12512
12513     /**
12514      * Returns the number of elements in this composite
12515      * @return Number
12516      */
12517     getCount : function(){
12518         return this.elements.length;
12519     },
12520
12521     /**
12522      * Returns true if this composite contains the passed element
12523      * @return Boolean
12524      */
12525     contains : function(el){
12526         return this.indexOf(el) !== -1;
12527     },
12528
12529     /**
12530      * Returns true if this composite contains the passed element
12531      * @return Boolean
12532      */
12533     indexOf : function(el){
12534         return this.elements.indexOf(Roo.get(el));
12535     },
12536
12537
12538     /**
12539     * Removes the specified element(s).
12540     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
12541     * or an array of any of those.
12542     * @param {Boolean} removeDom (optional) True to also remove the element from the document
12543     * @return {CompositeElement} this
12544     */
12545     removeElement : function(el, removeDom){
12546         if(el instanceof Array){
12547             for(var i = 0, len = el.length; i < len; i++){
12548                 this.removeElement(el[i]);
12549             }
12550             return this;
12551         }
12552         var index = typeof el == 'number' ? el : this.indexOf(el);
12553         if(index !== -1){
12554             if(removeDom){
12555                 var d = this.elements[index];
12556                 if(d.dom){
12557                     d.remove();
12558                 }else{
12559                     d.parentNode.removeChild(d);
12560                 }
12561             }
12562             this.elements.splice(index, 1);
12563         }
12564         return this;
12565     },
12566
12567     /**
12568     * Replaces the specified element with the passed element.
12569     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
12570     * to replace.
12571     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
12572     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
12573     * @return {CompositeElement} this
12574     */
12575     replaceElement : function(el, replacement, domReplace){
12576         var index = typeof el == 'number' ? el : this.indexOf(el);
12577         if(index !== -1){
12578             if(domReplace){
12579                 this.elements[index].replaceWith(replacement);
12580             }else{
12581                 this.elements.splice(index, 1, Roo.get(replacement))
12582             }
12583         }
12584         return this;
12585     },
12586
12587     /**
12588      * Removes all elements.
12589      */
12590     clear : function(){
12591         this.elements = [];
12592     }
12593 };
12594 (function(){
12595     Roo.CompositeElement.createCall = function(proto, fnName){
12596         if(!proto[fnName]){
12597             proto[fnName] = function(){
12598                 return this.invoke(fnName, arguments);
12599             };
12600         }
12601     };
12602     for(var fnName in Roo.Element.prototype){
12603         if(typeof Roo.Element.prototype[fnName] == "function"){
12604             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
12605         }
12606     };
12607 })();
12608 /*
12609  * Based on:
12610  * Ext JS Library 1.1.1
12611  * Copyright(c) 2006-2007, Ext JS, LLC.
12612  *
12613  * Originally Released Under LGPL - original licence link has changed is not relivant.
12614  *
12615  * Fork - LGPL
12616  * <script type="text/javascript">
12617  */
12618
12619 /**
12620  * @class Roo.CompositeElementLite
12621  * @extends Roo.CompositeElement
12622  * Flyweight composite class. Reuses the same Roo.Element for element operations.
12623  <pre><code>
12624  var els = Roo.select("#some-el div.some-class");
12625  // or select directly from an existing element
12626  var el = Roo.get('some-el');
12627  el.select('div.some-class');
12628
12629  els.setWidth(100); // all elements become 100 width
12630  els.hide(true); // all elements fade out and hide
12631  // or
12632  els.setWidth(100).hide(true);
12633  </code></pre><br><br>
12634  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
12635  * actions will be performed on all the elements in this collection.</b>
12636  */
12637 Roo.CompositeElementLite = function(els){
12638     Roo.CompositeElementLite.superclass.constructor.call(this, els);
12639     this.el = new Roo.Element.Flyweight();
12640 };
12641 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
12642     addElements : function(els){
12643         if(els){
12644             if(els instanceof Array){
12645                 this.elements = this.elements.concat(els);
12646             }else{
12647                 var yels = this.elements;
12648                 var index = yels.length-1;
12649                 for(var i = 0, len = els.length; i < len; i++) {
12650                     yels[++index] = els[i];
12651                 }
12652             }
12653         }
12654         return this;
12655     },
12656     invoke : function(fn, args){
12657         var els = this.elements;
12658         var el = this.el;
12659         for(var i = 0, len = els.length; i < len; i++) {
12660             el.dom = els[i];
12661                 Roo.Element.prototype[fn].apply(el, args);
12662         }
12663         return this;
12664     },
12665     /**
12666      * Returns a flyweight Element of the dom element object at the specified index
12667      * @param {Number} index
12668      * @return {Roo.Element}
12669      */
12670     item : function(index){
12671         if(!this.elements[index]){
12672             return null;
12673         }
12674         this.el.dom = this.elements[index];
12675         return this.el;
12676     },
12677
12678     // fixes scope with flyweight
12679     addListener : function(eventName, handler, scope, opt){
12680         var els = this.elements;
12681         for(var i = 0, len = els.length; i < len; i++) {
12682             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
12683         }
12684         return this;
12685     },
12686
12687     /**
12688     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
12689     * passed is the flyweight (shared) Roo.Element instance, so if you require a
12690     * a reference to the dom node, use el.dom.</b>
12691     * @param {Function} fn The function to call
12692     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
12693     * @return {CompositeElement} this
12694     */
12695     each : function(fn, scope){
12696         var els = this.elements;
12697         var el = this.el;
12698         for(var i = 0, len = els.length; i < len; i++){
12699             el.dom = els[i];
12700                 if(fn.call(scope || el, el, this, i) === false){
12701                 break;
12702             }
12703         }
12704         return this;
12705     },
12706
12707     indexOf : function(el){
12708         return this.elements.indexOf(Roo.getDom(el));
12709     },
12710
12711     replaceElement : function(el, replacement, domReplace){
12712         var index = typeof el == 'number' ? el : this.indexOf(el);
12713         if(index !== -1){
12714             replacement = Roo.getDom(replacement);
12715             if(domReplace){
12716                 var d = this.elements[index];
12717                 d.parentNode.insertBefore(replacement, d);
12718                 d.parentNode.removeChild(d);
12719             }
12720             this.elements.splice(index, 1, replacement);
12721         }
12722         return this;
12723     }
12724 });
12725 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
12726
12727 /*
12728  * Based on:
12729  * Ext JS Library 1.1.1
12730  * Copyright(c) 2006-2007, Ext JS, LLC.
12731  *
12732  * Originally Released Under LGPL - original licence link has changed is not relivant.
12733  *
12734  * Fork - LGPL
12735  * <script type="text/javascript">
12736  */
12737
12738  
12739
12740 /**
12741  * @class Roo.data.Connection
12742  * @extends Roo.util.Observable
12743  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
12744  * either to a configured URL, or to a URL specified at request time. 
12745  * 
12746  * Requests made by this class are asynchronous, and will return immediately. No data from
12747  * the server will be available to the statement immediately following the {@link #request} call.
12748  * To process returned data, use a callback in the request options object, or an event listener.
12749  * 
12750  * Note: If you are doing a file upload, you will not get a normal response object sent back to
12751  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
12752  * The response object is created using the innerHTML of the IFRAME's document as the responseText
12753  * property and, if present, the IFRAME's XML document as the responseXML property.
12754  * 
12755  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
12756  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
12757  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
12758  * standard DOM methods.
12759  * @constructor
12760  * @param {Object} config a configuration object.
12761  */
12762 Roo.data.Connection = function(config){
12763     Roo.apply(this, config);
12764     this.addEvents({
12765         /**
12766          * @event beforerequest
12767          * Fires before a network request is made to retrieve a data object.
12768          * @param {Connection} conn This Connection object.
12769          * @param {Object} options The options config object passed to the {@link #request} method.
12770          */
12771         "beforerequest" : true,
12772         /**
12773          * @event requestcomplete
12774          * Fires if the request was successfully completed.
12775          * @param {Connection} conn This Connection object.
12776          * @param {Object} response The XHR object containing the response data.
12777          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
12778          * @param {Object} options The options config object passed to the {@link #request} method.
12779          */
12780         "requestcomplete" : true,
12781         /**
12782          * @event requestexception
12783          * Fires if an error HTTP status was returned from the server.
12784          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
12785          * @param {Connection} conn This Connection object.
12786          * @param {Object} response The XHR object containing the response data.
12787          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
12788          * @param {Object} options The options config object passed to the {@link #request} method.
12789          */
12790         "requestexception" : true
12791     });
12792     Roo.data.Connection.superclass.constructor.call(this);
12793 };
12794
12795 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
12796     /**
12797      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12798      */
12799     /**
12800      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12801      * extra parameters to each request made by this object. (defaults to undefined)
12802      */
12803     /**
12804      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12805      *  to each request made by this object. (defaults to undefined)
12806      */
12807     /**
12808      * @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)
12809      */
12810     /**
12811      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12812      */
12813     timeout : 30000,
12814     /**
12815      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12816      * @type Boolean
12817      */
12818     autoAbort:false,
12819
12820     /**
12821      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12822      * @type Boolean
12823      */
12824     disableCaching: true,
12825
12826     /**
12827      * Sends an HTTP request to a remote server.
12828      * @param {Object} options An object which may contain the following properties:<ul>
12829      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
12830      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
12831      * request, a url encoded string or a function to call to get either.</li>
12832      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
12833      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
12834      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
12835      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
12836      * <li>options {Object} The parameter to the request call.</li>
12837      * <li>success {Boolean} True if the request succeeded.</li>
12838      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
12839      * </ul></li>
12840      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
12841      * The callback is passed the following parameters:<ul>
12842      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
12843      * <li>options {Object} The parameter to the request call.</li>
12844      * </ul></li>
12845      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
12846      * The callback is passed the following parameters:<ul>
12847      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
12848      * <li>options {Object} The parameter to the request call.</li>
12849      * </ul></li>
12850      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
12851      * for the callback function. Defaults to the browser window.</li>
12852      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
12853      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
12854      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
12855      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
12856      * params for the post data. Any params will be appended to the URL.</li>
12857      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
12858      * </ul>
12859      * @return {Number} transactionId
12860      */
12861     request : function(o){
12862         if(this.fireEvent("beforerequest", this, o) !== false){
12863             var p = o.params;
12864
12865             if(typeof p == "function"){
12866                 p = p.call(o.scope||window, o);
12867             }
12868             if(typeof p == "object"){
12869                 p = Roo.urlEncode(o.params);
12870             }
12871             if(this.extraParams){
12872                 var extras = Roo.urlEncode(this.extraParams);
12873                 p = p ? (p + '&' + extras) : extras;
12874             }
12875
12876             var url = o.url || this.url;
12877             if(typeof url == 'function'){
12878                 url = url.call(o.scope||window, o);
12879             }
12880
12881             if(o.form){
12882                 var form = Roo.getDom(o.form);
12883                 url = url || form.action;
12884
12885                 var enctype = form.getAttribute("enctype");
12886                 
12887                 if (o.formData) {
12888                     return this.doFormDataUpload(o, url);
12889                 }
12890                 
12891                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
12892                     return this.doFormUpload(o, p, url);
12893                 }
12894                 var f = Roo.lib.Ajax.serializeForm(form);
12895                 p = p ? (p + '&' + f) : f;
12896             }
12897             
12898             if (!o.form && o.formData) {
12899                 o.formData = o.formData === true ? new FormData() : o.formData;
12900                 for (var k in o.params) {
12901                     o.formData.append(k,o.params[k]);
12902                 }
12903                     
12904                 return this.doFormDataUpload(o, url);
12905             }
12906             
12907
12908             var hs = o.headers;
12909             if(this.defaultHeaders){
12910                 hs = Roo.apply(hs || {}, this.defaultHeaders);
12911                 if(!o.headers){
12912                     o.headers = hs;
12913                 }
12914             }
12915
12916             var cb = {
12917                 success: this.handleResponse,
12918                 failure: this.handleFailure,
12919                 scope: this,
12920                 argument: {options: o},
12921                 timeout : o.timeout || this.timeout
12922             };
12923
12924             var method = o.method||this.method||(p ? "POST" : "GET");
12925
12926             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
12927                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
12928             }
12929
12930             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
12931                 if(o.autoAbort){
12932                     this.abort();
12933                 }
12934             }else if(this.autoAbort !== false){
12935                 this.abort();
12936             }
12937
12938             if((method == 'GET' && p) || o.xmlData){
12939                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
12940                 p = '';
12941             }
12942             Roo.lib.Ajax.useDefaultHeader = typeof(o.headers) == 'undefined' || typeof(o.headers['Content-Type']) == 'undefined';
12943             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
12944             Roo.lib.Ajax.useDefaultHeader == true;
12945             return this.transId;
12946         }else{
12947             Roo.callback(o.callback, o.scope, [o, null, null]);
12948             return null;
12949         }
12950     },
12951
12952     /**
12953      * Determine whether this object has a request outstanding.
12954      * @param {Number} transactionId (Optional) defaults to the last transaction
12955      * @return {Boolean} True if there is an outstanding request.
12956      */
12957     isLoading : function(transId){
12958         if(transId){
12959             return Roo.lib.Ajax.isCallInProgress(transId);
12960         }else{
12961             return this.transId ? true : false;
12962         }
12963     },
12964
12965     /**
12966      * Aborts any outstanding request.
12967      * @param {Number} transactionId (Optional) defaults to the last transaction
12968      */
12969     abort : function(transId){
12970         if(transId || this.isLoading()){
12971             Roo.lib.Ajax.abort(transId || this.transId);
12972         }
12973     },
12974
12975     // private
12976     handleResponse : function(response){
12977         this.transId = false;
12978         var options = response.argument.options;
12979         response.argument = options ? options.argument : null;
12980         this.fireEvent("requestcomplete", this, response, options);
12981         Roo.callback(options.success, options.scope, [response, options]);
12982         Roo.callback(options.callback, options.scope, [options, true, response]);
12983     },
12984
12985     // private
12986     handleFailure : function(response, e){
12987         this.transId = false;
12988         var options = response.argument.options;
12989         response.argument = options ? options.argument : null;
12990         this.fireEvent("requestexception", this, response, options, e);
12991         Roo.callback(options.failure, options.scope, [response, options]);
12992         Roo.callback(options.callback, options.scope, [options, false, response]);
12993     },
12994
12995     // private
12996     doFormUpload : function(o, ps, url){
12997         var id = Roo.id();
12998         var frame = document.createElement('iframe');
12999         frame.id = id;
13000         frame.name = id;
13001         frame.className = 'x-hidden';
13002         if(Roo.isIE){
13003             frame.src = Roo.SSL_SECURE_URL;
13004         }
13005         document.body.appendChild(frame);
13006
13007         if(Roo.isIE){
13008            document.frames[id].name = id;
13009         }
13010
13011         var form = Roo.getDom(o.form);
13012         form.target = id;
13013         form.method = 'POST';
13014         form.enctype = form.encoding = 'multipart/form-data';
13015         if(url){
13016             form.action = url;
13017         }
13018
13019         var hiddens, hd;
13020         if(ps){ // add dynamic params
13021             hiddens = [];
13022             ps = Roo.urlDecode(ps, false);
13023             for(var k in ps){
13024                 if(ps.hasOwnProperty(k)){
13025                     hd = document.createElement('input');
13026                     hd.type = 'hidden';
13027                     hd.name = k;
13028                     hd.value = ps[k];
13029                     form.appendChild(hd);
13030                     hiddens.push(hd);
13031                 }
13032             }
13033         }
13034
13035         function cb(){
13036             var r = {  // bogus response object
13037                 responseText : '',
13038                 responseXML : null
13039             };
13040
13041             r.argument = o ? o.argument : null;
13042
13043             try { //
13044                 var doc;
13045                 if(Roo.isIE){
13046                     doc = frame.contentWindow.document;
13047                 }else {
13048                     doc = (frame.contentDocument || window.frames[id].document);
13049                 }
13050                 if(doc && doc.body){
13051                     r.responseText = doc.body.innerHTML;
13052                 }
13053                 if(doc && doc.XMLDocument){
13054                     r.responseXML = doc.XMLDocument;
13055                 }else {
13056                     r.responseXML = doc;
13057                 }
13058             }
13059             catch(e) {
13060                 // ignore
13061             }
13062
13063             Roo.EventManager.removeListener(frame, 'load', cb, this);
13064
13065             this.fireEvent("requestcomplete", this, r, o);
13066             Roo.callback(o.success, o.scope, [r, o]);
13067             Roo.callback(o.callback, o.scope, [o, true, r]);
13068
13069             setTimeout(function(){document.body.removeChild(frame);}, 100);
13070         }
13071
13072         Roo.EventManager.on(frame, 'load', cb, this);
13073         form.submit();
13074
13075         if(hiddens){ // remove dynamic params
13076             for(var i = 0, len = hiddens.length; i < len; i++){
13077                 form.removeChild(hiddens[i]);
13078             }
13079         }
13080     },
13081     // this is a 'formdata version???'
13082     
13083     
13084     doFormDataUpload : function(o,  url)
13085     {
13086         var formData;
13087         if (o.form) {
13088             var form =  Roo.getDom(o.form);
13089             form.enctype = form.encoding = 'multipart/form-data';
13090             formData = o.formData === true ? new FormData(form) : o.formData;
13091         } else {
13092             formData = o.formData === true ? new FormData() : o.formData;
13093         }
13094         
13095       
13096         var cb = {
13097             success: this.handleResponse,
13098             failure: this.handleFailure,
13099             scope: this,
13100             argument: {options: o},
13101             timeout : o.timeout || this.timeout
13102         };
13103  
13104         if(typeof o.autoAbort == 'boolean'){ // options gets top priority
13105             if(o.autoAbort){
13106                 this.abort();
13107             }
13108         }else if(this.autoAbort !== false){
13109             this.abort();
13110         }
13111
13112         //Roo.lib.Ajax.defaultPostHeader = null;
13113         Roo.lib.Ajax.useDefaultHeader = false;
13114         this.transId = Roo.lib.Ajax.request( "POST", url, cb,  formData, o);
13115         Roo.lib.Ajax.useDefaultHeader = true;
13116  
13117          
13118     }
13119     
13120 });
13121 /*
13122  * Based on:
13123  * Ext JS Library 1.1.1
13124  * Copyright(c) 2006-2007, Ext JS, LLC.
13125  *
13126  * Originally Released Under LGPL - original licence link has changed is not relivant.
13127  *
13128  * Fork - LGPL
13129  * <script type="text/javascript">
13130  */
13131  
13132 /**
13133  * Global Ajax request class.
13134  * 
13135  * @class Roo.Ajax
13136  * @extends Roo.data.Connection
13137  * @static
13138  * 
13139  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
13140  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
13141  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
13142  * @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)
13143  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
13144  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
13145  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
13146  */
13147 Roo.Ajax = new Roo.data.Connection({
13148     // fix up the docs
13149     /**
13150      * @scope Roo.Ajax
13151      * @type {Boolear} 
13152      */
13153     autoAbort : false,
13154
13155     /**
13156      * Serialize the passed form into a url encoded string
13157      * @scope Roo.Ajax
13158      * @param {String/HTMLElement} form
13159      * @return {String}
13160      */
13161     serializeForm : function(form){
13162         return Roo.lib.Ajax.serializeForm(form);
13163     }
13164 });/*
13165  * Based on:
13166  * Ext JS Library 1.1.1
13167  * Copyright(c) 2006-2007, Ext JS, LLC.
13168  *
13169  * Originally Released Under LGPL - original licence link has changed is not relivant.
13170  *
13171  * Fork - LGPL
13172  * <script type="text/javascript">
13173  */
13174
13175  
13176 /**
13177  * @class Roo.UpdateManager
13178  * @extends Roo.util.Observable
13179  * Provides AJAX-style update for Element object.<br><br>
13180  * Usage:<br>
13181  * <pre><code>
13182  * // Get it from a Roo.Element object
13183  * var el = Roo.get("foo");
13184  * var mgr = el.getUpdateManager();
13185  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
13186  * ...
13187  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
13188  * <br>
13189  * // or directly (returns the same UpdateManager instance)
13190  * var mgr = new Roo.UpdateManager("myElementId");
13191  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
13192  * mgr.on("update", myFcnNeedsToKnow);
13193  * <br>
13194    // short handed call directly from the element object
13195    Roo.get("foo").load({
13196         url: "bar.php",
13197         scripts:true,
13198         params: "for=bar",
13199         text: "Loading Foo..."
13200    });
13201  * </code></pre>
13202  * @constructor
13203  * Create new UpdateManager directly.
13204  * @param {String/HTMLElement/Roo.Element} el The element to update
13205  * @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).
13206  */
13207 Roo.UpdateManager = function(el, forceNew){
13208     el = Roo.get(el);
13209     if(!forceNew && el.updateManager){
13210         return el.updateManager;
13211     }
13212     /**
13213      * The Element object
13214      * @type Roo.Element
13215      */
13216     this.el = el;
13217     /**
13218      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
13219      * @type String
13220      */
13221     this.defaultUrl = null;
13222
13223     this.addEvents({
13224         /**
13225          * @event beforeupdate
13226          * Fired before an update is made, return false from your handler and the update is cancelled.
13227          * @param {Roo.Element} el
13228          * @param {String/Object/Function} url
13229          * @param {String/Object} params
13230          */
13231         "beforeupdate": true,
13232         /**
13233          * @event update
13234          * Fired after successful update is made.
13235          * @param {Roo.Element} el
13236          * @param {Object} oResponseObject The response Object
13237          */
13238         "update": true,
13239         /**
13240          * @event failure
13241          * Fired on update failure.
13242          * @param {Roo.Element} el
13243          * @param {Object} oResponseObject The response Object
13244          */
13245         "failure": true
13246     });
13247     var d = Roo.UpdateManager.defaults;
13248     /**
13249      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
13250      * @type String
13251      */
13252     this.sslBlankUrl = d.sslBlankUrl;
13253     /**
13254      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
13255      * @type Boolean
13256      */
13257     this.disableCaching = d.disableCaching;
13258     /**
13259      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
13260      * @type String
13261      */
13262     this.indicatorText = d.indicatorText;
13263     /**
13264      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
13265      * @type String
13266      */
13267     this.showLoadIndicator = d.showLoadIndicator;
13268     /**
13269      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
13270      * @type Number
13271      */
13272     this.timeout = d.timeout;
13273
13274     /**
13275      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
13276      * @type Boolean
13277      */
13278     this.loadScripts = d.loadScripts;
13279
13280     /**
13281      * Transaction object of current executing transaction
13282      */
13283     this.transaction = null;
13284
13285     /**
13286      * @private
13287      */
13288     this.autoRefreshProcId = null;
13289     /**
13290      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
13291      * @type Function
13292      */
13293     this.refreshDelegate = this.refresh.createDelegate(this);
13294     /**
13295      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
13296      * @type Function
13297      */
13298     this.updateDelegate = this.update.createDelegate(this);
13299     /**
13300      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
13301      * @type Function
13302      */
13303     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
13304     /**
13305      * @private
13306      */
13307     this.successDelegate = this.processSuccess.createDelegate(this);
13308     /**
13309      * @private
13310      */
13311     this.failureDelegate = this.processFailure.createDelegate(this);
13312
13313     if(!this.renderer){
13314      /**
13315       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
13316       */
13317     this.renderer = new Roo.UpdateManager.BasicRenderer();
13318     }
13319     
13320     Roo.UpdateManager.superclass.constructor.call(this);
13321 };
13322
13323 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
13324     /**
13325      * Get the Element this UpdateManager is bound to
13326      * @return {Roo.Element} The element
13327      */
13328     getEl : function(){
13329         return this.el;
13330     },
13331     /**
13332      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
13333      * @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:
13334 <pre><code>
13335 um.update({<br/>
13336     url: "your-url.php",<br/>
13337     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
13338     callback: yourFunction,<br/>
13339     scope: yourObject, //(optional scope)  <br/>
13340     discardUrl: false, <br/>
13341     nocache: false,<br/>
13342     text: "Loading...",<br/>
13343     timeout: 30,<br/>
13344     scripts: false<br/>
13345 });
13346 </code></pre>
13347      * The only required property is url. The optional properties nocache, text and scripts
13348      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
13349      * @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}
13350      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
13351      * @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.
13352      */
13353     update : function(url, params, callback, discardUrl){
13354         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
13355             var method = this.method,
13356                 cfg;
13357             if(typeof url == "object"){ // must be config object
13358                 cfg = url;
13359                 url = cfg.url;
13360                 params = params || cfg.params;
13361                 callback = callback || cfg.callback;
13362                 discardUrl = discardUrl || cfg.discardUrl;
13363                 if(callback && cfg.scope){
13364                     callback = callback.createDelegate(cfg.scope);
13365                 }
13366                 if(typeof cfg.method != "undefined"){method = cfg.method;};
13367                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
13368                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
13369                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
13370                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
13371             }
13372             this.showLoading();
13373             if(!discardUrl){
13374                 this.defaultUrl = url;
13375             }
13376             if(typeof url == "function"){
13377                 url = url.call(this);
13378             }
13379
13380             method = method || (params ? "POST" : "GET");
13381             if(method == "GET"){
13382                 url = this.prepareUrl(url);
13383             }
13384
13385             var o = Roo.apply(cfg ||{}, {
13386                 url : url,
13387                 params: params,
13388                 success: this.successDelegate,
13389                 failure: this.failureDelegate,
13390                 callback: undefined,
13391                 timeout: (this.timeout*1000),
13392                 argument: {"url": url, "form": null, "callback": callback, "params": params}
13393             });
13394             Roo.log("updated manager called with timeout of " + o.timeout);
13395             this.transaction = Roo.Ajax.request(o);
13396         }
13397     },
13398
13399     /**
13400      * 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.
13401      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
13402      * @param {String/HTMLElement} form The form Id or form element
13403      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
13404      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
13405      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
13406      */
13407     formUpdate : function(form, url, reset, callback){
13408         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
13409             if(typeof url == "function"){
13410                 url = url.call(this);
13411             }
13412             form = Roo.getDom(form);
13413             this.transaction = Roo.Ajax.request({
13414                 form: form,
13415                 url:url,
13416                 success: this.successDelegate,
13417                 failure: this.failureDelegate,
13418                 timeout: (this.timeout*1000),
13419                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
13420             });
13421             this.showLoading.defer(1, this);
13422         }
13423     },
13424
13425     /**
13426      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
13427      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
13428      */
13429     refresh : function(callback){
13430         if(this.defaultUrl == null){
13431             return;
13432         }
13433         this.update(this.defaultUrl, null, callback, true);
13434     },
13435
13436     /**
13437      * Set this element to auto refresh.
13438      * @param {Number} interval How often to update (in seconds).
13439      * @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)
13440      * @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}
13441      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
13442      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
13443      */
13444     startAutoRefresh : function(interval, url, params, callback, refreshNow){
13445         if(refreshNow){
13446             this.update(url || this.defaultUrl, params, callback, true);
13447         }
13448         if(this.autoRefreshProcId){
13449             clearInterval(this.autoRefreshProcId);
13450         }
13451         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
13452     },
13453
13454     /**
13455      * Stop auto refresh on this element.
13456      */
13457      stopAutoRefresh : function(){
13458         if(this.autoRefreshProcId){
13459             clearInterval(this.autoRefreshProcId);
13460             delete this.autoRefreshProcId;
13461         }
13462     },
13463
13464     isAutoRefreshing : function(){
13465        return this.autoRefreshProcId ? true : false;
13466     },
13467     /**
13468      * Called to update the element to "Loading" state. Override to perform custom action.
13469      */
13470     showLoading : function(){
13471         if(this.showLoadIndicator){
13472             this.el.update(this.indicatorText);
13473         }
13474     },
13475
13476     /**
13477      * Adds unique parameter to query string if disableCaching = true
13478      * @private
13479      */
13480     prepareUrl : function(url){
13481         if(this.disableCaching){
13482             var append = "_dc=" + (new Date().getTime());
13483             if(url.indexOf("?") !== -1){
13484                 url += "&" + append;
13485             }else{
13486                 url += "?" + append;
13487             }
13488         }
13489         return url;
13490     },
13491
13492     /**
13493      * @private
13494      */
13495     processSuccess : function(response){
13496         this.transaction = null;
13497         if(response.argument.form && response.argument.reset){
13498             try{ // put in try/catch since some older FF releases had problems with this
13499                 response.argument.form.reset();
13500             }catch(e){}
13501         }
13502         if(this.loadScripts){
13503             this.renderer.render(this.el, response, this,
13504                 this.updateComplete.createDelegate(this, [response]));
13505         }else{
13506             this.renderer.render(this.el, response, this);
13507             this.updateComplete(response);
13508         }
13509     },
13510
13511     updateComplete : function(response){
13512         this.fireEvent("update", this.el, response);
13513         if(typeof response.argument.callback == "function"){
13514             response.argument.callback(this.el, true, response);
13515         }
13516     },
13517
13518     /**
13519      * @private
13520      */
13521     processFailure : function(response){
13522         this.transaction = null;
13523         this.fireEvent("failure", this.el, response);
13524         if(typeof response.argument.callback == "function"){
13525             response.argument.callback(this.el, false, response);
13526         }
13527     },
13528
13529     /**
13530      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
13531      * @param {Object} renderer The object implementing the render() method
13532      */
13533     setRenderer : function(renderer){
13534         this.renderer = renderer;
13535     },
13536
13537     getRenderer : function(){
13538        return this.renderer;
13539     },
13540
13541     /**
13542      * Set the defaultUrl used for updates
13543      * @param {String/Function} defaultUrl The url or a function to call to get the url
13544      */
13545     setDefaultUrl : function(defaultUrl){
13546         this.defaultUrl = defaultUrl;
13547     },
13548
13549     /**
13550      * Aborts the executing transaction
13551      */
13552     abort : function(){
13553         if(this.transaction){
13554             Roo.Ajax.abort(this.transaction);
13555         }
13556     },
13557
13558     /**
13559      * Returns true if an update is in progress
13560      * @return {Boolean}
13561      */
13562     isUpdating : function(){
13563         if(this.transaction){
13564             return Roo.Ajax.isLoading(this.transaction);
13565         }
13566         return false;
13567     }
13568 });
13569
13570 /**
13571  * @class Roo.UpdateManager.defaults
13572  * @static (not really - but it helps the doc tool)
13573  * The defaults collection enables customizing the default properties of UpdateManager
13574  */
13575    Roo.UpdateManager.defaults = {
13576        /**
13577          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
13578          * @type Number
13579          */
13580          timeout : 30,
13581
13582          /**
13583          * True to process scripts by default (Defaults to false).
13584          * @type Boolean
13585          */
13586         loadScripts : false,
13587
13588         /**
13589         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
13590         * @type String
13591         */
13592         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
13593         /**
13594          * Whether to append unique parameter on get request to disable caching (Defaults to false).
13595          * @type Boolean
13596          */
13597         disableCaching : false,
13598         /**
13599          * Whether to show indicatorText when loading (Defaults to true).
13600          * @type Boolean
13601          */
13602         showLoadIndicator : true,
13603         /**
13604          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
13605          * @type String
13606          */
13607         indicatorText : '<div class="loading-indicator">Loading...</div>'
13608    };
13609
13610 /**
13611  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
13612  *Usage:
13613  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
13614  * @param {String/HTMLElement/Roo.Element} el The element to update
13615  * @param {String} url The url
13616  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
13617  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
13618  * @static
13619  * @deprecated
13620  * @member Roo.UpdateManager
13621  */
13622 Roo.UpdateManager.updateElement = function(el, url, params, options){
13623     var um = Roo.get(el, true).getUpdateManager();
13624     Roo.apply(um, options);
13625     um.update(url, params, options ? options.callback : null);
13626 };
13627 // alias for backwards compat
13628 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
13629 /**
13630  * @class Roo.UpdateManager.BasicRenderer
13631  * Default Content renderer. Updates the elements innerHTML with the responseText.
13632  */
13633 Roo.UpdateManager.BasicRenderer = function(){};
13634
13635 Roo.UpdateManager.BasicRenderer.prototype = {
13636     /**
13637      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
13638      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
13639      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
13640      * @param {Roo.Element} el The element being rendered
13641      * @param {Object} response The YUI Connect response object
13642      * @param {UpdateManager} updateManager The calling update manager
13643      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
13644      */
13645      render : function(el, response, updateManager, callback){
13646         el.update(response.responseText, updateManager.loadScripts, callback);
13647     }
13648 };
13649 /*
13650  * Based on:
13651  * Roo JS
13652  * (c)) Alan Knowles
13653  * Licence : LGPL
13654  */
13655
13656
13657 /**
13658  * @class Roo.DomTemplate
13659  * @extends Roo.Template
13660  * An effort at a dom based template engine..
13661  *
13662  * Similar to XTemplate, except it uses dom parsing to create the template..
13663  *
13664  * Supported features:
13665  *
13666  *  Tags:
13667
13668 <pre><code>
13669       {a_variable} - output encoded.
13670       {a_variable.format:("Y-m-d")} - call a method on the variable
13671       {a_variable:raw} - unencoded output
13672       {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
13673       {a_variable:this.method_on_template(...)} - call a method on the template object.
13674  
13675 </code></pre>
13676  *  The tpl tag:
13677 <pre><code>
13678         &lt;div roo-for="a_variable or condition.."&gt;&lt;/div&gt;
13679         &lt;div roo-if="a_variable or condition"&gt;&lt;/div&gt;
13680         &lt;div roo-exec="some javascript"&gt;&lt;/div&gt;
13681         &lt;div roo-name="named_template"&gt;&lt;/div&gt; 
13682   
13683 </code></pre>
13684  *      
13685  */
13686 Roo.DomTemplate = function()
13687 {
13688      Roo.DomTemplate.superclass.constructor.apply(this, arguments);
13689      if (this.html) {
13690         this.compile();
13691      }
13692 };
13693
13694
13695 Roo.extend(Roo.DomTemplate, Roo.Template, {
13696     /**
13697      * id counter for sub templates.
13698      */
13699     id : 0,
13700     /**
13701      * flag to indicate if dom parser is inside a pre,
13702      * it will strip whitespace if not.
13703      */
13704     inPre : false,
13705     
13706     /**
13707      * The various sub templates
13708      */
13709     tpls : false,
13710     
13711     
13712     
13713     /**
13714      *
13715      * basic tag replacing syntax
13716      * WORD:WORD()
13717      *
13718      * // you can fake an object call by doing this
13719      *  x.t:(test,tesT) 
13720      * 
13721      */
13722     re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
13723     //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
13724     
13725     iterChild : function (node, method) {
13726         
13727         var oldPre = this.inPre;
13728         if (node.tagName == 'PRE') {
13729             this.inPre = true;
13730         }
13731         for( var i = 0; i < node.childNodes.length; i++) {
13732             method.call(this, node.childNodes[i]);
13733         }
13734         this.inPre = oldPre;
13735     },
13736     
13737     
13738     
13739     /**
13740      * compile the template
13741      *
13742      * This is not recursive, so I'm not sure how nested templates are really going to be handled..
13743      *
13744      */
13745     compile: function()
13746     {
13747         var s = this.html;
13748         
13749         // covert the html into DOM...
13750         var doc = false;
13751         var div =false;
13752         try {
13753             doc = document.implementation.createHTMLDocument("");
13754             doc.documentElement.innerHTML =   this.html  ;
13755             div = doc.documentElement;
13756         } catch (e) {
13757             // old IE... - nasty -- it causes all sorts of issues.. with
13758             // images getting pulled from server..
13759             div = document.createElement('div');
13760             div.innerHTML = this.html;
13761         }
13762         //doc.documentElement.innerHTML = htmlBody
13763          
13764         
13765         
13766         this.tpls = [];
13767         var _t = this;
13768         this.iterChild(div, function(n) {_t.compileNode(n, true); });
13769         
13770         var tpls = this.tpls;
13771         
13772         // create a top level template from the snippet..
13773         
13774         //Roo.log(div.innerHTML);
13775         
13776         var tpl = {
13777             uid : 'master',
13778             id : this.id++,
13779             attr : false,
13780             value : false,
13781             body : div.innerHTML,
13782             
13783             forCall : false,
13784             execCall : false,
13785             dom : div,
13786             isTop : true
13787             
13788         };
13789         tpls.unshift(tpl);
13790         
13791         
13792         // compile them...
13793         this.tpls = [];
13794         Roo.each(tpls, function(tp){
13795             this.compileTpl(tp);
13796             this.tpls[tp.id] = tp;
13797         }, this);
13798         
13799         this.master = tpls[0];
13800         return this;
13801         
13802         
13803     },
13804     
13805     compileNode : function(node, istop) {
13806         // test for
13807         //Roo.log(node);
13808         
13809         
13810         // skip anything not a tag..
13811         if (node.nodeType != 1) {
13812             if (node.nodeType == 3 && !this.inPre) {
13813                 // reduce white space..
13814                 node.nodeValue = node.nodeValue.replace(/\s+/g, ' '); 
13815                 
13816             }
13817             return;
13818         }
13819         
13820         var tpl = {
13821             uid : false,
13822             id : false,
13823             attr : false,
13824             value : false,
13825             body : '',
13826             
13827             forCall : false,
13828             execCall : false,
13829             dom : false,
13830             isTop : istop
13831             
13832             
13833         };
13834         
13835         
13836         switch(true) {
13837             case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
13838             case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
13839             case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
13840             case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
13841             // no default..
13842         }
13843         
13844         
13845         if (!tpl.attr) {
13846             // just itterate children..
13847             this.iterChild(node,this.compileNode);
13848             return;
13849         }
13850         tpl.uid = this.id++;
13851         tpl.value = node.getAttribute('roo-' +  tpl.attr);
13852         node.removeAttribute('roo-'+ tpl.attr);
13853         if (tpl.attr != 'name') {
13854             var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
13855             node.parentNode.replaceChild(placeholder,  node);
13856         } else {
13857             
13858             var placeholder =  document.createElement('span');
13859             placeholder.className = 'roo-tpl-' + tpl.value;
13860             node.parentNode.replaceChild(placeholder,  node);
13861         }
13862         
13863         // parent now sees '{domtplXXXX}
13864         this.iterChild(node,this.compileNode);
13865         
13866         // we should now have node body...
13867         var div = document.createElement('div');
13868         div.appendChild(node);
13869         tpl.dom = node;
13870         // this has the unfortunate side effect of converting tagged attributes
13871         // eg. href="{...}" into %7C...%7D
13872         // this has been fixed by searching for those combo's although it's a bit hacky..
13873         
13874         
13875         tpl.body = div.innerHTML;
13876         
13877         
13878          
13879         tpl.id = tpl.uid;
13880         switch(tpl.attr) {
13881             case 'for' :
13882                 switch (tpl.value) {
13883                     case '.':  tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
13884                     case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
13885                     default:   tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
13886                 }
13887                 break;
13888             
13889             case 'exec':
13890                 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
13891                 break;
13892             
13893             case 'if':     
13894                 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
13895                 break;
13896             
13897             case 'name':
13898                 tpl.id  = tpl.value; // replace non characters???
13899                 break;
13900             
13901         }
13902         
13903         
13904         this.tpls.push(tpl);
13905         
13906         
13907         
13908     },
13909     
13910     
13911     
13912     
13913     /**
13914      * Compile a segment of the template into a 'sub-template'
13915      *
13916      * 
13917      * 
13918      *
13919      */
13920     compileTpl : function(tpl)
13921     {
13922         var fm = Roo.util.Format;
13923         var useF = this.disableFormats !== true;
13924         
13925         var sep = Roo.isGecko ? "+\n" : ",\n";
13926         
13927         var undef = function(str) {
13928             Roo.debug && Roo.log("Property not found :"  + str);
13929             return '';
13930         };
13931           
13932         //Roo.log(tpl.body);
13933         
13934         
13935         
13936         var fn = function(m, lbrace, name, format, args)
13937         {
13938             //Roo.log("ARGS");
13939             //Roo.log(arguments);
13940             args = args ? args.replace(/\\'/g,"'") : args;
13941             //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
13942             if (typeof(format) == 'undefined') {
13943                 format =  'htmlEncode'; 
13944             }
13945             if (format == 'raw' ) {
13946                 format = false;
13947             }
13948             
13949             if(name.substr(0, 6) == 'domtpl'){
13950                 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
13951             }
13952             
13953             // build an array of options to determine if value is undefined..
13954             
13955             // basically get 'xxxx.yyyy' then do
13956             // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
13957             //    (function () { Roo.log("Property not found"); return ''; })() :
13958             //    ......
13959             
13960             var udef_ar = [];
13961             var lookfor = '';
13962             Roo.each(name.split('.'), function(st) {
13963                 lookfor += (lookfor.length ? '.': '') + st;
13964                 udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
13965             });
13966             
13967             var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
13968             
13969             
13970             if(format && useF){
13971                 
13972                 args = args ? ',' + args : "";
13973                  
13974                 if(format.substr(0, 5) != "this."){
13975                     format = "fm." + format + '(';
13976                 }else{
13977                     format = 'this.call("'+ format.substr(5) + '", ';
13978                     args = ", values";
13979                 }
13980                 
13981                 return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
13982             }
13983              
13984             if (args && args.length) {
13985                 // called with xxyx.yuu:(test,test)
13986                 // change to ()
13987                 return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
13988             }
13989             // raw.. - :raw modifier..
13990             return "'"+ sep + udef_st  + name + ")"+sep+"'";
13991             
13992         };
13993         var body;
13994         // branched to use + in gecko and [].join() in others
13995         if(Roo.isGecko){
13996             body = "tpl.compiled = function(values, parent){  with(values) { return '" +
13997                    tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
13998                     "';};};";
13999         }else{
14000             body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
14001             body.push(tpl.body.replace(/(\r\n|\n)/g,
14002                             '\\n').replace(/'/g, "\\'").replace(this.re, fn));
14003             body.push("'].join('');};};");
14004             body = body.join('');
14005         }
14006         
14007         Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
14008        
14009         /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
14010         eval(body);
14011         
14012         return this;
14013     },
14014      
14015     /**
14016      * same as applyTemplate, except it's done to one of the subTemplates
14017      * when using named templates, you can do:
14018      *
14019      * var str = pl.applySubTemplate('your-name', values);
14020      *
14021      * 
14022      * @param {Number} id of the template
14023      * @param {Object} values to apply to template
14024      * @param {Object} parent (normaly the instance of this object)
14025      */
14026     applySubTemplate : function(id, values, parent)
14027     {
14028         
14029         
14030         var t = this.tpls[id];
14031         
14032         
14033         try { 
14034             if(t.ifCall && !t.ifCall.call(this, values, parent)){
14035                 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
14036                 return '';
14037             }
14038         } catch(e) {
14039             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
14040             Roo.log(values);
14041           
14042             return '';
14043         }
14044         try { 
14045             
14046             if(t.execCall && t.execCall.call(this, values, parent)){
14047                 return '';
14048             }
14049         } catch(e) {
14050             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
14051             Roo.log(values);
14052             return '';
14053         }
14054         
14055         try {
14056             var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
14057             parent = t.target ? values : parent;
14058             if(t.forCall && vs instanceof Array){
14059                 var buf = [];
14060                 for(var i = 0, len = vs.length; i < len; i++){
14061                     try {
14062                         buf[buf.length] = t.compiled.call(this, vs[i], 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(vs[i]);
14068                     }   
14069                 }
14070                 return buf.join('');
14071             }
14072         } catch (e) {
14073             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
14074             Roo.log(values);
14075             return '';
14076         }
14077         try {
14078             return t.compiled.call(this, vs, parent);
14079         } catch (e) {
14080             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
14081             Roo.log(e.body);
14082             //Roo.log(t.compiled);
14083             Roo.log(values);
14084             return '';
14085         }
14086     },
14087
14088    
14089
14090     applyTemplate : function(values){
14091         return this.master.compiled.call(this, values, {});
14092         //var s = this.subs;
14093     },
14094
14095     apply : function(){
14096         return this.applyTemplate.apply(this, arguments);
14097     }
14098
14099  });
14100
14101 Roo.DomTemplate.from = function(el){
14102     el = Roo.getDom(el);
14103     return new Roo.Domtemplate(el.value || el.innerHTML);
14104 };/*
14105  * Based on:
14106  * Ext JS Library 1.1.1
14107  * Copyright(c) 2006-2007, Ext JS, LLC.
14108  *
14109  * Originally Released Under LGPL - original licence link has changed is not relivant.
14110  *
14111  * Fork - LGPL
14112  * <script type="text/javascript">
14113  */
14114
14115 /**
14116  * @class Roo.util.DelayedTask
14117  * Provides a convenient method of performing setTimeout where a new
14118  * timeout cancels the old timeout. An example would be performing validation on a keypress.
14119  * You can use this class to buffer
14120  * the keypress events for a certain number of milliseconds, and perform only if they stop
14121  * for that amount of time.
14122  * @constructor The parameters to this constructor serve as defaults and are not required.
14123  * @param {Function} fn (optional) The default function to timeout
14124  * @param {Object} scope (optional) The default scope of that timeout
14125  * @param {Array} args (optional) The default Array of arguments
14126  */
14127 Roo.util.DelayedTask = function(fn, scope, args){
14128     var id = null, d, t;
14129
14130     var call = function(){
14131         var now = new Date().getTime();
14132         if(now - t >= d){
14133             clearInterval(id);
14134             id = null;
14135             fn.apply(scope, args || []);
14136         }
14137     };
14138     /**
14139      * Cancels any pending timeout and queues a new one
14140      * @param {Number} delay The milliseconds to delay
14141      * @param {Function} newFn (optional) Overrides function passed to constructor
14142      * @param {Object} newScope (optional) Overrides scope passed to constructor
14143      * @param {Array} newArgs (optional) Overrides args passed to constructor
14144      */
14145     this.delay = function(delay, newFn, newScope, newArgs){
14146         if(id && delay != d){
14147             this.cancel();
14148         }
14149         d = delay;
14150         t = new Date().getTime();
14151         fn = newFn || fn;
14152         scope = newScope || scope;
14153         args = newArgs || args;
14154         if(!id){
14155             id = setInterval(call, d);
14156         }
14157     };
14158
14159     /**
14160      * Cancel the last queued timeout
14161      */
14162     this.cancel = function(){
14163         if(id){
14164             clearInterval(id);
14165             id = null;
14166         }
14167     };
14168 };/*
14169  * Based on:
14170  * Ext JS Library 1.1.1
14171  * Copyright(c) 2006-2007, Ext JS, LLC.
14172  *
14173  * Originally Released Under LGPL - original licence link has changed is not relivant.
14174  *
14175  * Fork - LGPL
14176  * <script type="text/javascript">
14177  */
14178 /**
14179  * @class Roo.util.TaskRunner
14180  * Manage background tasks - not sure why this is better that setInterval?
14181  * @static
14182  *
14183  */
14184  
14185 Roo.util.TaskRunner = function(interval){
14186     interval = interval || 10;
14187     var tasks = [], removeQueue = [];
14188     var id = 0;
14189     var running = false;
14190
14191     var stopThread = function(){
14192         running = false;
14193         clearInterval(id);
14194         id = 0;
14195     };
14196
14197     var startThread = function(){
14198         if(!running){
14199             running = true;
14200             id = setInterval(runTasks, interval);
14201         }
14202     };
14203
14204     var removeTask = function(task){
14205         removeQueue.push(task);
14206         if(task.onStop){
14207             task.onStop();
14208         }
14209     };
14210
14211     var runTasks = function(){
14212         if(removeQueue.length > 0){
14213             for(var i = 0, len = removeQueue.length; i < len; i++){
14214                 tasks.remove(removeQueue[i]);
14215             }
14216             removeQueue = [];
14217             if(tasks.length < 1){
14218                 stopThread();
14219                 return;
14220             }
14221         }
14222         var now = new Date().getTime();
14223         for(var i = 0, len = tasks.length; i < len; ++i){
14224             var t = tasks[i];
14225             var itime = now - t.taskRunTime;
14226             if(t.interval <= itime){
14227                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
14228                 t.taskRunTime = now;
14229                 if(rt === false || t.taskRunCount === t.repeat){
14230                     removeTask(t);
14231                     return;
14232                 }
14233             }
14234             if(t.duration && t.duration <= (now - t.taskStartTime)){
14235                 removeTask(t);
14236             }
14237         }
14238     };
14239
14240     /**
14241      * Queues a new task.
14242      * @param {Object} task
14243      *
14244      * Task property : interval = how frequent to run.
14245      * Task object should implement
14246      * function run()
14247      * Task object may implement
14248      * function onStop()
14249      */
14250     this.start = function(task){
14251         tasks.push(task);
14252         task.taskStartTime = new Date().getTime();
14253         task.taskRunTime = 0;
14254         task.taskRunCount = 0;
14255         startThread();
14256         return task;
14257     };
14258     /**
14259      * Stop  new task.
14260      * @param {Object} task
14261      */
14262     this.stop = function(task){
14263         removeTask(task);
14264         return task;
14265     };
14266     /**
14267      * Stop all Tasks
14268      */
14269     this.stopAll = function(){
14270         stopThread();
14271         for(var i = 0, len = tasks.length; i < len; i++){
14272             if(tasks[i].onStop){
14273                 tasks[i].onStop();
14274             }
14275         }
14276         tasks = [];
14277         removeQueue = [];
14278     };
14279 };
14280
14281 Roo.TaskMgr = new Roo.util.TaskRunner();/*
14282  * Based on:
14283  * Ext JS Library 1.1.1
14284  * Copyright(c) 2006-2007, Ext JS, LLC.
14285  *
14286  * Originally Released Under LGPL - original licence link has changed is not relivant.
14287  *
14288  * Fork - LGPL
14289  * <script type="text/javascript">
14290  */
14291
14292  
14293 /**
14294  * @class Roo.util.MixedCollection
14295  * @extends Roo.util.Observable
14296  * A Collection class that maintains both numeric indexes and keys and exposes events.
14297  * @constructor
14298  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
14299  * collection (defaults to false)
14300  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
14301  * and return the key value for that item.  This is used when available to look up the key on items that
14302  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
14303  * equivalent to providing an implementation for the {@link #getKey} method.
14304  */
14305 Roo.util.MixedCollection = function(allowFunctions, keyFn){
14306     this.items = [];
14307     this.map = {};
14308     this.keys = [];
14309     this.length = 0;
14310     this.addEvents({
14311         /**
14312          * @event clear
14313          * Fires when the collection is cleared.
14314          */
14315         "clear" : true,
14316         /**
14317          * @event add
14318          * Fires when an item is added to the collection.
14319          * @param {Number} index The index at which the item was added.
14320          * @param {Object} o The item added.
14321          * @param {String} key The key associated with the added item.
14322          */
14323         "add" : true,
14324         /**
14325          * @event replace
14326          * Fires when an item is replaced in the collection.
14327          * @param {String} key he key associated with the new added.
14328          * @param {Object} old The item being replaced.
14329          * @param {Object} new The new item.
14330          */
14331         "replace" : true,
14332         /**
14333          * @event remove
14334          * Fires when an item is removed from the collection.
14335          * @param {Object} o The item being removed.
14336          * @param {String} key (optional) The key associated with the removed item.
14337          */
14338         "remove" : true,
14339         "sort" : true
14340     });
14341     this.allowFunctions = allowFunctions === true;
14342     if(keyFn){
14343         this.getKey = keyFn;
14344     }
14345     Roo.util.MixedCollection.superclass.constructor.call(this);
14346 };
14347
14348 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
14349     allowFunctions : false,
14350     
14351 /**
14352  * Adds an item to the collection.
14353  * @param {String} key The key to associate with the item
14354  * @param {Object} o The item to add.
14355  * @return {Object} The item added.
14356  */
14357     add : function(key, o){
14358         if(arguments.length == 1){
14359             o = arguments[0];
14360             key = this.getKey(o);
14361         }
14362         if(typeof key == "undefined" || key === null){
14363             this.length++;
14364             this.items.push(o);
14365             this.keys.push(null);
14366         }else{
14367             var old = this.map[key];
14368             if(old){
14369                 return this.replace(key, o);
14370             }
14371             this.length++;
14372             this.items.push(o);
14373             this.map[key] = o;
14374             this.keys.push(key);
14375         }
14376         this.fireEvent("add", this.length-1, o, key);
14377         return o;
14378     },
14379        
14380 /**
14381   * MixedCollection has a generic way to fetch keys if you implement getKey.
14382 <pre><code>
14383 // normal way
14384 var mc = new Roo.util.MixedCollection();
14385 mc.add(someEl.dom.id, someEl);
14386 mc.add(otherEl.dom.id, otherEl);
14387 //and so on
14388
14389 // using getKey
14390 var mc = new Roo.util.MixedCollection();
14391 mc.getKey = function(el){
14392    return el.dom.id;
14393 };
14394 mc.add(someEl);
14395 mc.add(otherEl);
14396
14397 // or via the constructor
14398 var mc = new Roo.util.MixedCollection(false, function(el){
14399    return el.dom.id;
14400 });
14401 mc.add(someEl);
14402 mc.add(otherEl);
14403 </code></pre>
14404  * @param o {Object} The item for which to find the key.
14405  * @return {Object} The key for the passed item.
14406  */
14407     getKey : function(o){
14408          return o.id; 
14409     },
14410    
14411 /**
14412  * Replaces an item in the collection.
14413  * @param {String} key The key associated with the item to replace, or the item to replace.
14414  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
14415  * @return {Object}  The new item.
14416  */
14417     replace : function(key, o){
14418         if(arguments.length == 1){
14419             o = arguments[0];
14420             key = this.getKey(o);
14421         }
14422         var old = this.item(key);
14423         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
14424              return this.add(key, o);
14425         }
14426         var index = this.indexOfKey(key);
14427         this.items[index] = o;
14428         this.map[key] = o;
14429         this.fireEvent("replace", key, old, o);
14430         return o;
14431     },
14432    
14433 /**
14434  * Adds all elements of an Array or an Object to the collection.
14435  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
14436  * an Array of values, each of which are added to the collection.
14437  */
14438     addAll : function(objs){
14439         if(arguments.length > 1 || objs instanceof Array){
14440             var args = arguments.length > 1 ? arguments : objs;
14441             for(var i = 0, len = args.length; i < len; i++){
14442                 this.add(args[i]);
14443             }
14444         }else{
14445             for(var key in objs){
14446                 if(this.allowFunctions || typeof objs[key] != "function"){
14447                     this.add(key, objs[key]);
14448                 }
14449             }
14450         }
14451     },
14452    
14453 /**
14454  * Executes the specified function once for every item in the collection, passing each
14455  * item as the first and only parameter. returning false from the function will stop the iteration.
14456  * @param {Function} fn The function to execute for each item.
14457  * @param {Object} scope (optional) The scope in which to execute the function.
14458  */
14459     each : function(fn, scope){
14460         var items = [].concat(this.items); // each safe for removal
14461         for(var i = 0, len = items.length; i < len; i++){
14462             if(fn.call(scope || items[i], items[i], i, len) === false){
14463                 break;
14464             }
14465         }
14466     },
14467    
14468 /**
14469  * Executes the specified function once for every key in the collection, passing each
14470  * key, and its associated item as the first two parameters.
14471  * @param {Function} fn The function to execute for each item.
14472  * @param {Object} scope (optional) The scope in which to execute the function.
14473  */
14474     eachKey : function(fn, scope){
14475         for(var i = 0, len = this.keys.length; i < len; i++){
14476             fn.call(scope || window, this.keys[i], this.items[i], i, len);
14477         }
14478     },
14479    
14480 /**
14481  * Returns the first item in the collection which elicits a true return value from the
14482  * passed selection function.
14483  * @param {Function} fn The selection function to execute for each item.
14484  * @param {Object} scope (optional) The scope in which to execute the function.
14485  * @return {Object} The first item in the collection which returned true from the selection function.
14486  */
14487     find : function(fn, scope){
14488         for(var i = 0, len = this.items.length; i < len; i++){
14489             if(fn.call(scope || window, this.items[i], this.keys[i])){
14490                 return this.items[i];
14491             }
14492         }
14493         return null;
14494     },
14495    
14496 /**
14497  * Inserts an item at the specified index in the collection.
14498  * @param {Number} index The index to insert the item at.
14499  * @param {String} key The key to associate with the new item, or the item itself.
14500  * @param {Object} o  (optional) If the second parameter was a key, the new item.
14501  * @return {Object} The item inserted.
14502  */
14503     insert : function(index, key, o){
14504         if(arguments.length == 2){
14505             o = arguments[1];
14506             key = this.getKey(o);
14507         }
14508         if(index >= this.length){
14509             return this.add(key, o);
14510         }
14511         this.length++;
14512         this.items.splice(index, 0, o);
14513         if(typeof key != "undefined" && key != null){
14514             this.map[key] = o;
14515         }
14516         this.keys.splice(index, 0, key);
14517         this.fireEvent("add", index, o, key);
14518         return o;
14519     },
14520    
14521 /**
14522  * Removed an item from the collection.
14523  * @param {Object} o The item to remove.
14524  * @return {Object} The item removed.
14525  */
14526     remove : function(o){
14527         return this.removeAt(this.indexOf(o));
14528     },
14529    
14530 /**
14531  * Remove an item from a specified index in the collection.
14532  * @param {Number} index The index within the collection of the item to remove.
14533  */
14534     removeAt : function(index){
14535         if(index < this.length && index >= 0){
14536             this.length--;
14537             var o = this.items[index];
14538             this.items.splice(index, 1);
14539             var key = this.keys[index];
14540             if(typeof key != "undefined"){
14541                 delete this.map[key];
14542             }
14543             this.keys.splice(index, 1);
14544             this.fireEvent("remove", o, key);
14545         }
14546     },
14547    
14548 /**
14549  * Removed an item associated with the passed key fom the collection.
14550  * @param {String} key The key of the item to remove.
14551  */
14552     removeKey : function(key){
14553         return this.removeAt(this.indexOfKey(key));
14554     },
14555    
14556 /**
14557  * Returns the number of items in the collection.
14558  * @return {Number} the number of items in the collection.
14559  */
14560     getCount : function(){
14561         return this.length; 
14562     },
14563    
14564 /**
14565  * Returns index within the collection of the passed Object.
14566  * @param {Object} o The item to find the index of.
14567  * @return {Number} index of the item.
14568  */
14569     indexOf : function(o){
14570         if(!this.items.indexOf){
14571             for(var i = 0, len = this.items.length; i < len; i++){
14572                 if(this.items[i] == o) {
14573                     return i;
14574                 }
14575             }
14576             return -1;
14577         }else{
14578             return this.items.indexOf(o);
14579         }
14580     },
14581    
14582 /**
14583  * Returns index within the collection of the passed key.
14584  * @param {String} key The key to find the index of.
14585  * @return {Number} index of the key.
14586  */
14587     indexOfKey : function(key){
14588         if(!this.keys.indexOf){
14589             for(var i = 0, len = this.keys.length; i < len; i++){
14590                 if(this.keys[i] == key) {
14591                     return i;
14592                 }
14593             }
14594             return -1;
14595         }else{
14596             return this.keys.indexOf(key);
14597         }
14598     },
14599    
14600 /**
14601  * Returns the item associated with the passed key OR index. Key has priority over index.
14602  * @param {String/Number} key The key or index of the item.
14603  * @return {Object} The item associated with the passed key.
14604  */
14605     item : function(key){
14606         if (key === 'length') {
14607             return null;
14608         }
14609         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
14610         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
14611     },
14612     
14613 /**
14614  * Returns the item at the specified index.
14615  * @param {Number} index The index of the item.
14616  * @return {Object}
14617  */
14618     itemAt : function(index){
14619         return this.items[index];
14620     },
14621     
14622 /**
14623  * Returns the item associated with the passed key.
14624  * @param {String/Number} key The key of the item.
14625  * @return {Object} The item associated with the passed key.
14626  */
14627     key : function(key){
14628         return this.map[key];
14629     },
14630    
14631 /**
14632  * Returns true if the collection contains the passed Object as an item.
14633  * @param {Object} o  The Object to look for in the collection.
14634  * @return {Boolean} True if the collection contains the Object as an item.
14635  */
14636     contains : function(o){
14637         return this.indexOf(o) != -1;
14638     },
14639    
14640 /**
14641  * Returns true if the collection contains the passed Object as a key.
14642  * @param {String} key The key to look for in the collection.
14643  * @return {Boolean} True if the collection contains the Object as a key.
14644  */
14645     containsKey : function(key){
14646         return typeof this.map[key] != "undefined";
14647     },
14648    
14649 /**
14650  * Removes all items from the collection.
14651  */
14652     clear : function(){
14653         this.length = 0;
14654         this.items = [];
14655         this.keys = [];
14656         this.map = {};
14657         this.fireEvent("clear");
14658     },
14659    
14660 /**
14661  * Returns the first item in the collection.
14662  * @return {Object} the first item in the collection..
14663  */
14664     first : function(){
14665         return this.items[0]; 
14666     },
14667    
14668 /**
14669  * Returns the last item in the collection.
14670  * @return {Object} the last item in the collection..
14671  */
14672     last : function(){
14673         return this.items[this.length-1];   
14674     },
14675     
14676     _sort : function(property, dir, fn){
14677         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
14678         fn = fn || function(a, b){
14679             return a-b;
14680         };
14681         var c = [], k = this.keys, items = this.items;
14682         for(var i = 0, len = items.length; i < len; i++){
14683             c[c.length] = {key: k[i], value: items[i], index: i};
14684         }
14685         c.sort(function(a, b){
14686             var v = fn(a[property], b[property]) * dsc;
14687             if(v == 0){
14688                 v = (a.index < b.index ? -1 : 1);
14689             }
14690             return v;
14691         });
14692         for(var i = 0, len = c.length; i < len; i++){
14693             items[i] = c[i].value;
14694             k[i] = c[i].key;
14695         }
14696         this.fireEvent("sort", this);
14697     },
14698     
14699     /**
14700      * Sorts this collection with the passed comparison function
14701      * @param {String} direction (optional) "ASC" or "DESC"
14702      * @param {Function} fn (optional) comparison function
14703      */
14704     sort : function(dir, fn){
14705         this._sort("value", dir, fn);
14706     },
14707     
14708     /**
14709      * Sorts this collection by keys
14710      * @param {String} direction (optional) "ASC" or "DESC"
14711      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
14712      */
14713     keySort : function(dir, fn){
14714         this._sort("key", dir, fn || function(a, b){
14715             return String(a).toUpperCase()-String(b).toUpperCase();
14716         });
14717     },
14718     
14719     /**
14720      * Returns a range of items in this collection
14721      * @param {Number} startIndex (optional) defaults to 0
14722      * @param {Number} endIndex (optional) default to the last item
14723      * @return {Array} An array of items
14724      */
14725     getRange : function(start, end){
14726         var items = this.items;
14727         if(items.length < 1){
14728             return [];
14729         }
14730         start = start || 0;
14731         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
14732         var r = [];
14733         if(start <= end){
14734             for(var i = start; i <= end; i++) {
14735                     r[r.length] = items[i];
14736             }
14737         }else{
14738             for(var i = start; i >= end; i--) {
14739                     r[r.length] = items[i];
14740             }
14741         }
14742         return r;
14743     },
14744         
14745     /**
14746      * Filter the <i>objects</i> in this collection by a specific property. 
14747      * Returns a new collection that has been filtered.
14748      * @param {String} property A property on your objects
14749      * @param {String/RegExp} value Either string that the property values 
14750      * should start with or a RegExp to test against the property
14751      * @return {MixedCollection} The new filtered collection
14752      */
14753     filter : function(property, value){
14754         if(!value.exec){ // not a regex
14755             value = String(value);
14756             if(value.length == 0){
14757                 return this.clone();
14758             }
14759             value = new RegExp("^" + Roo.escapeRe(value), "i");
14760         }
14761         return this.filterBy(function(o){
14762             return o && value.test(o[property]);
14763         });
14764         },
14765     
14766     /**
14767      * Filter by a function. * Returns a new collection that has been filtered.
14768      * The passed function will be called with each 
14769      * object in the collection. If the function returns true, the value is included 
14770      * otherwise it is filtered.
14771      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
14772      * @param {Object} scope (optional) The scope of the function (defaults to this) 
14773      * @return {MixedCollection} The new filtered collection
14774      */
14775     filterBy : function(fn, scope){
14776         var r = new Roo.util.MixedCollection();
14777         r.getKey = this.getKey;
14778         var k = this.keys, it = this.items;
14779         for(var i = 0, len = it.length; i < len; i++){
14780             if(fn.call(scope||this, it[i], k[i])){
14781                                 r.add(k[i], it[i]);
14782                         }
14783         }
14784         return r;
14785     },
14786     
14787     /**
14788      * Creates a duplicate of this collection
14789      * @return {MixedCollection}
14790      */
14791     clone : function(){
14792         var r = new Roo.util.MixedCollection();
14793         var k = this.keys, it = this.items;
14794         for(var i = 0, len = it.length; i < len; i++){
14795             r.add(k[i], it[i]);
14796         }
14797         r.getKey = this.getKey;
14798         return r;
14799     }
14800 });
14801 /**
14802  * Returns the item associated with the passed key or index.
14803  * @method
14804  * @param {String/Number} key The key or index of the item.
14805  * @return {Object} The item associated with the passed key.
14806  */
14807 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
14808  * Based on:
14809  * Ext JS Library 1.1.1
14810  * Copyright(c) 2006-2007, Ext JS, LLC.
14811  *
14812  * Originally Released Under LGPL - original licence link has changed is not relivant.
14813  *
14814  * Fork - LGPL
14815  * <script type="text/javascript">
14816  */
14817 /**
14818  * @class Roo.util.JSON
14819  * Modified version of Douglas Crockford"s json.js that doesn"t
14820  * mess with the Object prototype 
14821  * http://www.json.org/js.html
14822  * @static
14823  */
14824 Roo.util.JSON = new (function(){
14825     var useHasOwn = {}.hasOwnProperty ? true : false;
14826     
14827     // crashes Safari in some instances
14828     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
14829     
14830     var pad = function(n) {
14831         return n < 10 ? "0" + n : n;
14832     };
14833     
14834     var m = {
14835         "\b": '\\b',
14836         "\t": '\\t',
14837         "\n": '\\n',
14838         "\f": '\\f',
14839         "\r": '\\r',
14840         '"' : '\\"',
14841         "\\": '\\\\'
14842     };
14843
14844     var encodeString = function(s){
14845         if (/["\\\x00-\x1f]/.test(s)) {
14846             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
14847                 var c = m[b];
14848                 if(c){
14849                     return c;
14850                 }
14851                 c = b.charCodeAt();
14852                 return "\\u00" +
14853                     Math.floor(c / 16).toString(16) +
14854                     (c % 16).toString(16);
14855             }) + '"';
14856         }
14857         return '"' + s + '"';
14858     };
14859     
14860     var encodeArray = function(o){
14861         var a = ["["], b, i, l = o.length, v;
14862             for (i = 0; i < l; i += 1) {
14863                 v = o[i];
14864                 switch (typeof v) {
14865                     case "undefined":
14866                     case "function":
14867                     case "unknown":
14868                         break;
14869                     default:
14870                         if (b) {
14871                             a.push(',');
14872                         }
14873                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
14874                         b = true;
14875                 }
14876             }
14877             a.push("]");
14878             return a.join("");
14879     };
14880     
14881     var encodeDate = function(o){
14882         return '"' + o.getFullYear() + "-" +
14883                 pad(o.getMonth() + 1) + "-" +
14884                 pad(o.getDate()) + "T" +
14885                 pad(o.getHours()) + ":" +
14886                 pad(o.getMinutes()) + ":" +
14887                 pad(o.getSeconds()) + '"';
14888     };
14889     
14890     /**
14891      * Encodes an Object, Array or other value
14892      * @param {Mixed} o The variable to encode
14893      * @return {String} The JSON string
14894      */
14895     this.encode = function(o)
14896     {
14897         // should this be extended to fully wrap stringify..
14898         
14899         if(typeof o == "undefined" || o === null){
14900             return "null";
14901         }else if(o instanceof Array){
14902             return encodeArray(o);
14903         }else if(o instanceof Date){
14904             return encodeDate(o);
14905         }else if(typeof o == "string"){
14906             return encodeString(o);
14907         }else if(typeof o == "number"){
14908             return isFinite(o) ? String(o) : "null";
14909         }else if(typeof o == "boolean"){
14910             return String(o);
14911         }else {
14912             var a = ["{"], b, i, v;
14913             for (i in o) {
14914                 if(!useHasOwn || o.hasOwnProperty(i)) {
14915                     v = o[i];
14916                     switch (typeof v) {
14917                     case "undefined":
14918                     case "function":
14919                     case "unknown":
14920                         break;
14921                     default:
14922                         if(b){
14923                             a.push(',');
14924                         }
14925                         a.push(this.encode(i), ":",
14926                                 v === null ? "null" : this.encode(v));
14927                         b = true;
14928                     }
14929                 }
14930             }
14931             a.push("}");
14932             return a.join("");
14933         }
14934     };
14935     
14936     /**
14937      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
14938      * @param {String} json The JSON string
14939      * @return {Object} The resulting object
14940      */
14941     this.decode = function(json){
14942         
14943         return  /** eval:var:json */ eval("(" + json + ')');
14944     };
14945 })();
14946 /** 
14947  * Shorthand for {@link Roo.util.JSON#encode}
14948  * @member Roo encode 
14949  * @method */
14950 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
14951 /** 
14952  * Shorthand for {@link Roo.util.JSON#decode}
14953  * @member Roo decode 
14954  * @method */
14955 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
14956 /*
14957  * Based on:
14958  * Ext JS Library 1.1.1
14959  * Copyright(c) 2006-2007, Ext JS, LLC.
14960  *
14961  * Originally Released Under LGPL - original licence link has changed is not relivant.
14962  *
14963  * Fork - LGPL
14964  * <script type="text/javascript">
14965  */
14966  
14967 /**
14968  * @class Roo.util.Format
14969  * Reusable data formatting functions
14970  * @static
14971  */
14972 Roo.util.Format = function(){
14973     var trimRe = /^\s+|\s+$/g;
14974     return {
14975         /**
14976          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
14977          * @param {String} value The string to truncate
14978          * @param {Number} length The maximum length to allow before truncating
14979          * @return {String} The converted text
14980          */
14981         ellipsis : function(value, len){
14982             if(value && value.length > len){
14983                 return value.substr(0, len-3)+"...";
14984             }
14985             return value;
14986         },
14987
14988         /**
14989          * Checks a reference and converts it to empty string if it is undefined
14990          * @param {Mixed} value Reference to check
14991          * @return {Mixed} Empty string if converted, otherwise the original value
14992          */
14993         undef : function(value){
14994             return typeof value != "undefined" ? value : "";
14995         },
14996
14997         /**
14998          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
14999          * @param {String} value The string to encode
15000          * @return {String} The encoded text
15001          */
15002         htmlEncode : function(value){
15003             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
15004         },
15005
15006         /**
15007          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
15008          * @param {String} value The string to decode
15009          * @return {String} The decoded text
15010          */
15011         htmlDecode : function(value){
15012             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
15013         },
15014
15015         /**
15016          * Trims any whitespace from either side of a string
15017          * @param {String} value The text to trim
15018          * @return {String} The trimmed text
15019          */
15020         trim : function(value){
15021             return String(value).replace(trimRe, "");
15022         },
15023
15024         /**
15025          * Returns a substring from within an original string
15026          * @param {String} value The original text
15027          * @param {Number} start The start index of the substring
15028          * @param {Number} length The length of the substring
15029          * @return {String} The substring
15030          */
15031         substr : function(value, start, length){
15032             return String(value).substr(start, length);
15033         },
15034
15035         /**
15036          * Converts a string to all lower case letters
15037          * @param {String} value The text to convert
15038          * @return {String} The converted text
15039          */
15040         lowercase : function(value){
15041             return String(value).toLowerCase();
15042         },
15043
15044         /**
15045          * Converts a string to all upper case letters
15046          * @param {String} value The text to convert
15047          * @return {String} The converted text
15048          */
15049         uppercase : function(value){
15050             return String(value).toUpperCase();
15051         },
15052
15053         /**
15054          * Converts the first character only of a string to upper case
15055          * @param {String} value The text to convert
15056          * @return {String} The converted text
15057          */
15058         capitalize : function(value){
15059             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
15060         },
15061
15062         // private
15063         call : function(value, fn){
15064             if(arguments.length > 2){
15065                 var args = Array.prototype.slice.call(arguments, 2);
15066                 args.unshift(value);
15067                  
15068                 return /** eval:var:value */  eval(fn).apply(window, args);
15069             }else{
15070                 /** eval:var:value */
15071                 return /** eval:var:value */ eval(fn).call(window, value);
15072             }
15073         },
15074
15075        
15076         /**
15077          * safer version of Math.toFixed..??/
15078          * @param {Number/String} value The numeric value to format
15079          * @param {Number/String} value Decimal places 
15080          * @return {String} The formatted currency string
15081          */
15082         toFixed : function(v, n)
15083         {
15084             // why not use to fixed - precision is buggered???
15085             if (!n) {
15086                 return Math.round(v-0);
15087             }
15088             var fact = Math.pow(10,n+1);
15089             v = (Math.round((v-0)*fact))/fact;
15090             var z = (''+fact).substring(2);
15091             if (v == Math.floor(v)) {
15092                 return Math.floor(v) + '.' + z;
15093             }
15094             
15095             // now just padd decimals..
15096             var ps = String(v).split('.');
15097             var fd = (ps[1] + z);
15098             var r = fd.substring(0,n); 
15099             var rm = fd.substring(n); 
15100             if (rm < 5) {
15101                 return ps[0] + '.' + r;
15102             }
15103             r*=1; // turn it into a number;
15104             r++;
15105             if (String(r).length != n) {
15106                 ps[0]*=1;
15107                 ps[0]++;
15108                 r = String(r).substring(1); // chop the end off.
15109             }
15110             
15111             return ps[0] + '.' + r;
15112              
15113         },
15114         
15115         /**
15116          * Format a number as US currency
15117          * @param {Number/String} value The numeric value to format
15118          * @return {String} The formatted currency string
15119          */
15120         usMoney : function(v){
15121             return '$' + Roo.util.Format.number(v);
15122         },
15123         
15124         /**
15125          * Format a number
15126          * eventually this should probably emulate php's number_format
15127          * @param {Number/String} value The numeric value to format
15128          * @param {Number} decimals number of decimal places
15129          * @param {String} delimiter for thousands (default comma)
15130          * @return {String} The formatted currency string
15131          */
15132         number : function(v, decimals, thousandsDelimiter)
15133         {
15134             // multiply and round.
15135             decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
15136             thousandsDelimiter = typeof(thousandsDelimiter) == 'undefined' ? ',' : thousandsDelimiter;
15137             
15138             var mul = Math.pow(10, decimals);
15139             var zero = String(mul).substring(1);
15140             v = (Math.round((v-0)*mul))/mul;
15141             
15142             // if it's '0' number.. then
15143             
15144             //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
15145             v = String(v);
15146             var ps = v.split('.');
15147             var whole = ps[0];
15148             
15149             var r = /(\d+)(\d{3})/;
15150             // add comma's
15151             
15152             if(thousandsDelimiter.length != 0) {
15153                 whole = whole.replace(/\B(?=(\d{3})+(?!\d))/g, thousandsDelimiter );
15154             } 
15155             
15156             var sub = ps[1] ?
15157                     // has decimals..
15158                     (decimals ?  ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
15159                     // does not have decimals
15160                     (decimals ? ('.' + zero) : '');
15161             
15162             
15163             return whole + sub ;
15164         },
15165         
15166         /**
15167          * Parse a value into a formatted date using the specified format pattern.
15168          * @param {Mixed} value The value to format
15169          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
15170          * @return {String} The formatted date string
15171          */
15172         date : function(v, format){
15173             if(!v){
15174                 return "";
15175             }
15176             if(!(v instanceof Date)){
15177                 v = new Date(Date.parse(v));
15178             }
15179             return v.dateFormat(format || Roo.util.Format.defaults.date);
15180         },
15181
15182         /**
15183          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
15184          * @param {String} format Any valid date format string
15185          * @return {Function} The date formatting function
15186          */
15187         dateRenderer : function(format){
15188             return function(v){
15189                 return Roo.util.Format.date(v, format);  
15190             };
15191         },
15192
15193         // private
15194         stripTagsRE : /<\/?[^>]+>/gi,
15195         
15196         /**
15197          * Strips all HTML tags
15198          * @param {Mixed} value The text from which to strip tags
15199          * @return {String} The stripped text
15200          */
15201         stripTags : function(v){
15202             return !v ? v : String(v).replace(this.stripTagsRE, "");
15203         },
15204         
15205         /**
15206          * Size in Mb,Gb etc.
15207          * @param {Number} value The number to be formated
15208          * @param {number} decimals how many decimal places
15209          * @return {String} the formated string
15210          */
15211         size : function(value, decimals)
15212         {
15213             var sizes = ['b', 'k', 'M', 'G', 'T'];
15214             if (value == 0) {
15215                 return 0;
15216             }
15217             var i = parseInt(Math.floor(Math.log(value) / Math.log(1024)));
15218             return Roo.util.Format.number(value/ Math.pow(1024, i) ,decimals)   + sizes[i];
15219         }
15220         
15221         
15222         
15223     };
15224 }();
15225 Roo.util.Format.defaults = {
15226     date : 'd/M/Y'
15227 };/*
15228  * Based on:
15229  * Ext JS Library 1.1.1
15230  * Copyright(c) 2006-2007, Ext JS, LLC.
15231  *
15232  * Originally Released Under LGPL - original licence link has changed is not relivant.
15233  *
15234  * Fork - LGPL
15235  * <script type="text/javascript">
15236  */
15237
15238
15239  
15240
15241 /**
15242  * @class Roo.MasterTemplate
15243  * @extends Roo.Template
15244  * Provides a template that can have child templates. The syntax is:
15245 <pre><code>
15246 var t = new Roo.MasterTemplate(
15247         '&lt;select name="{name}"&gt;',
15248                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
15249         '&lt;/select&gt;'
15250 );
15251 t.add('options', {value: 'foo', text: 'bar'});
15252 // or you can add multiple child elements in one shot
15253 t.addAll('options', [
15254     {value: 'foo', text: 'bar'},
15255     {value: 'foo2', text: 'bar2'},
15256     {value: 'foo3', text: 'bar3'}
15257 ]);
15258 // then append, applying the master template values
15259 t.append('my-form', {name: 'my-select'});
15260 </code></pre>
15261 * A name attribute for the child template is not required if you have only one child
15262 * template or you want to refer to them by index.
15263  */
15264 Roo.MasterTemplate = function(){
15265     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
15266     this.originalHtml = this.html;
15267     var st = {};
15268     var m, re = this.subTemplateRe;
15269     re.lastIndex = 0;
15270     var subIndex = 0;
15271     while(m = re.exec(this.html)){
15272         var name = m[1], content = m[2];
15273         st[subIndex] = {
15274             name: name,
15275             index: subIndex,
15276             buffer: [],
15277             tpl : new Roo.Template(content)
15278         };
15279         if(name){
15280             st[name] = st[subIndex];
15281         }
15282         st[subIndex].tpl.compile();
15283         st[subIndex].tpl.call = this.call.createDelegate(this);
15284         subIndex++;
15285     }
15286     this.subCount = subIndex;
15287     this.subs = st;
15288 };
15289 Roo.extend(Roo.MasterTemplate, Roo.Template, {
15290     /**
15291     * The regular expression used to match sub templates
15292     * @type RegExp
15293     * @property
15294     */
15295     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
15296
15297     /**
15298      * Applies the passed values to a child template.
15299      * @param {String/Number} name (optional) The name or index of the child template
15300      * @param {Array/Object} values The values to be applied to the template
15301      * @return {MasterTemplate} this
15302      */
15303      add : function(name, values){
15304         if(arguments.length == 1){
15305             values = arguments[0];
15306             name = 0;
15307         }
15308         var s = this.subs[name];
15309         s.buffer[s.buffer.length] = s.tpl.apply(values);
15310         return this;
15311     },
15312
15313     /**
15314      * Applies all the passed values to a child template.
15315      * @param {String/Number} name (optional) The name or index of the child template
15316      * @param {Array} values The values to be applied to the template, this should be an array of objects.
15317      * @param {Boolean} reset (optional) True to reset the template first
15318      * @return {MasterTemplate} this
15319      */
15320     fill : function(name, values, reset){
15321         var a = arguments;
15322         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
15323             values = a[0];
15324             name = 0;
15325             reset = a[1];
15326         }
15327         if(reset){
15328             this.reset();
15329         }
15330         for(var i = 0, len = values.length; i < len; i++){
15331             this.add(name, values[i]);
15332         }
15333         return this;
15334     },
15335
15336     /**
15337      * Resets the template for reuse
15338      * @return {MasterTemplate} this
15339      */
15340      reset : function(){
15341         var s = this.subs;
15342         for(var i = 0; i < this.subCount; i++){
15343             s[i].buffer = [];
15344         }
15345         return this;
15346     },
15347
15348     applyTemplate : function(values){
15349         var s = this.subs;
15350         var replaceIndex = -1;
15351         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
15352             return s[++replaceIndex].buffer.join("");
15353         });
15354         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
15355     },
15356
15357     apply : function(){
15358         return this.applyTemplate.apply(this, arguments);
15359     },
15360
15361     compile : function(){return this;}
15362 });
15363
15364 /**
15365  * Alias for fill().
15366  * @method
15367  */
15368 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
15369  /**
15370  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
15371  * var tpl = Roo.MasterTemplate.from('element-id');
15372  * @param {String/HTMLElement} el
15373  * @param {Object} config
15374  * @static
15375  */
15376 Roo.MasterTemplate.from = function(el, config){
15377     el = Roo.getDom(el);
15378     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
15379 };/*
15380  * Based on:
15381  * Ext JS Library 1.1.1
15382  * Copyright(c) 2006-2007, Ext JS, LLC.
15383  *
15384  * Originally Released Under LGPL - original licence link has changed is not relivant.
15385  *
15386  * Fork - LGPL
15387  * <script type="text/javascript">
15388  */
15389
15390  
15391 /**
15392  * @class Roo.util.CSS
15393  * Utility class for manipulating CSS rules
15394  * @static
15395
15396  */
15397 Roo.util.CSS = function(){
15398         var rules = null;
15399         var doc = document;
15400
15401     var camelRe = /(-[a-z])/gi;
15402     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
15403
15404    return {
15405    /**
15406     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
15407     * tag and appended to the HEAD of the document.
15408     * @param {String|Object} cssText The text containing the css rules
15409     * @param {String} id An id to add to the stylesheet for later removal
15410     * @return {StyleSheet}
15411     */
15412     createStyleSheet : function(cssText, id){
15413         var ss;
15414         var head = doc.getElementsByTagName("head")[0];
15415         var nrules = doc.createElement("style");
15416         nrules.setAttribute("type", "text/css");
15417         if(id){
15418             nrules.setAttribute("id", id);
15419         }
15420         if (typeof(cssText) != 'string') {
15421             // support object maps..
15422             // not sure if this a good idea.. 
15423             // perhaps it should be merged with the general css handling
15424             // and handle js style props.
15425             var cssTextNew = [];
15426             for(var n in cssText) {
15427                 var citems = [];
15428                 for(var k in cssText[n]) {
15429                     citems.push( k + ' : ' +cssText[n][k] + ';' );
15430                 }
15431                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
15432                 
15433             }
15434             cssText = cssTextNew.join("\n");
15435             
15436         }
15437        
15438        
15439        if(Roo.isIE){
15440            head.appendChild(nrules);
15441            ss = nrules.styleSheet;
15442            ss.cssText = cssText;
15443        }else{
15444            try{
15445                 nrules.appendChild(doc.createTextNode(cssText));
15446            }catch(e){
15447                nrules.cssText = cssText; 
15448            }
15449            head.appendChild(nrules);
15450            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
15451        }
15452        this.cacheStyleSheet(ss);
15453        return ss;
15454    },
15455
15456    /**
15457     * Removes a style or link tag by id
15458     * @param {String} id The id of the tag
15459     */
15460    removeStyleSheet : function(id){
15461        var existing = doc.getElementById(id);
15462        if(existing){
15463            existing.parentNode.removeChild(existing);
15464        }
15465    },
15466
15467    /**
15468     * Dynamically swaps an existing stylesheet reference for a new one
15469     * @param {String} id The id of an existing link tag to remove
15470     * @param {String} url The href of the new stylesheet to include
15471     */
15472    swapStyleSheet : function(id, url){
15473        this.removeStyleSheet(id);
15474        var ss = doc.createElement("link");
15475        ss.setAttribute("rel", "stylesheet");
15476        ss.setAttribute("type", "text/css");
15477        ss.setAttribute("id", id);
15478        ss.setAttribute("href", url);
15479        doc.getElementsByTagName("head")[0].appendChild(ss);
15480    },
15481    
15482    /**
15483     * Refresh the rule cache if you have dynamically added stylesheets
15484     * @return {Object} An object (hash) of rules indexed by selector
15485     */
15486    refreshCache : function(){
15487        return this.getRules(true);
15488    },
15489
15490    // private
15491    cacheStyleSheet : function(stylesheet){
15492        if(!rules){
15493            rules = {};
15494        }
15495        try{// try catch for cross domain access issue
15496            var ssRules = stylesheet.cssRules || stylesheet.rules;
15497            for(var j = ssRules.length-1; j >= 0; --j){
15498                rules[ssRules[j].selectorText] = ssRules[j];
15499            }
15500        }catch(e){}
15501    },
15502    
15503    /**
15504     * Gets all css rules for the document
15505     * @param {Boolean} refreshCache true to refresh the internal cache
15506     * @return {Object} An object (hash) of rules indexed by selector
15507     */
15508    getRules : function(refreshCache){
15509                 if(rules == null || refreshCache){
15510                         rules = {};
15511                         var ds = doc.styleSheets;
15512                         for(var i =0, len = ds.length; i < len; i++){
15513                             try{
15514                         this.cacheStyleSheet(ds[i]);
15515                     }catch(e){} 
15516                 }
15517                 }
15518                 return rules;
15519         },
15520         
15521         /**
15522     * Gets an an individual CSS rule by selector(s)
15523     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
15524     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
15525     * @return {CSSRule} The CSS rule or null if one is not found
15526     */
15527    getRule : function(selector, refreshCache){
15528                 var rs = this.getRules(refreshCache);
15529                 if(!(selector instanceof Array)){
15530                     return rs[selector];
15531                 }
15532                 for(var i = 0; i < selector.length; i++){
15533                         if(rs[selector[i]]){
15534                                 return rs[selector[i]];
15535                         }
15536                 }
15537                 return null;
15538         },
15539         
15540         
15541         /**
15542     * Updates a rule property
15543     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
15544     * @param {String} property The css property
15545     * @param {String} value The new value for the property
15546     * @return {Boolean} true If a rule was found and updated
15547     */
15548    updateRule : function(selector, property, value){
15549                 if(!(selector instanceof Array)){
15550                         var rule = this.getRule(selector);
15551                         if(rule){
15552                                 rule.style[property.replace(camelRe, camelFn)] = value;
15553                                 return true;
15554                         }
15555                 }else{
15556                         for(var i = 0; i < selector.length; i++){
15557                                 if(this.updateRule(selector[i], property, value)){
15558                                         return true;
15559                                 }
15560                         }
15561                 }
15562                 return false;
15563         }
15564    };   
15565 }();/*
15566  * Based on:
15567  * Ext JS Library 1.1.1
15568  * Copyright(c) 2006-2007, Ext JS, LLC.
15569  *
15570  * Originally Released Under LGPL - original licence link has changed is not relivant.
15571  *
15572  * Fork - LGPL
15573  * <script type="text/javascript">
15574  */
15575
15576  
15577
15578 /**
15579  * @class Roo.util.ClickRepeater
15580  * @extends Roo.util.Observable
15581  * 
15582  * A wrapper class which can be applied to any element. Fires a "click" event while the
15583  * mouse is pressed. The interval between firings may be specified in the config but
15584  * defaults to 10 milliseconds.
15585  * 
15586  * Optionally, a CSS class may be applied to the element during the time it is pressed.
15587  * 
15588  * @cfg {String/HTMLElement/Element} el The element to act as a button.
15589  * @cfg {Number} delay The initial delay before the repeating event begins firing.
15590  * Similar to an autorepeat key delay.
15591  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
15592  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
15593  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
15594  *           "interval" and "delay" are ignored. "immediate" is honored.
15595  * @cfg {Boolean} preventDefault True to prevent the default click event
15596  * @cfg {Boolean} stopDefault True to stop the default click event
15597  * 
15598  * @history
15599  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
15600  *     2007-02-02 jvs Renamed to ClickRepeater
15601  *   2007-02-03 jvs Modifications for FF Mac and Safari 
15602  *
15603  *  @constructor
15604  * @param {String/HTMLElement/Element} el The element to listen on
15605  * @param {Object} config
15606  **/
15607 Roo.util.ClickRepeater = function(el, config)
15608 {
15609     this.el = Roo.get(el);
15610     this.el.unselectable();
15611
15612     Roo.apply(this, config);
15613
15614     this.addEvents({
15615     /**
15616      * @event mousedown
15617      * Fires when the mouse button is depressed.
15618      * @param {Roo.util.ClickRepeater} this
15619      */
15620         "mousedown" : true,
15621     /**
15622      * @event click
15623      * Fires on a specified interval during the time the element is pressed.
15624      * @param {Roo.util.ClickRepeater} this
15625      */
15626         "click" : true,
15627     /**
15628      * @event mouseup
15629      * Fires when the mouse key is released.
15630      * @param {Roo.util.ClickRepeater} this
15631      */
15632         "mouseup" : true
15633     });
15634
15635     this.el.on("mousedown", this.handleMouseDown, this);
15636     if(this.preventDefault || this.stopDefault){
15637         this.el.on("click", function(e){
15638             if(this.preventDefault){
15639                 e.preventDefault();
15640             }
15641             if(this.stopDefault){
15642                 e.stopEvent();
15643             }
15644         }, this);
15645     }
15646
15647     // allow inline handler
15648     if(this.handler){
15649         this.on("click", this.handler,  this.scope || this);
15650     }
15651
15652     Roo.util.ClickRepeater.superclass.constructor.call(this);
15653 };
15654
15655 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
15656     interval : 20,
15657     delay: 250,
15658     preventDefault : true,
15659     stopDefault : false,
15660     timer : 0,
15661
15662     // private
15663     handleMouseDown : function(){
15664         clearTimeout(this.timer);
15665         this.el.blur();
15666         if(this.pressClass){
15667             this.el.addClass(this.pressClass);
15668         }
15669         this.mousedownTime = new Date();
15670
15671         Roo.get(document).on("mouseup", this.handleMouseUp, this);
15672         this.el.on("mouseout", this.handleMouseOut, this);
15673
15674         this.fireEvent("mousedown", this);
15675         this.fireEvent("click", this);
15676         
15677         this.timer = this.click.defer(this.delay || this.interval, this);
15678     },
15679
15680     // private
15681     click : function(){
15682         this.fireEvent("click", this);
15683         this.timer = this.click.defer(this.getInterval(), this);
15684     },
15685
15686     // private
15687     getInterval: function(){
15688         if(!this.accelerate){
15689             return this.interval;
15690         }
15691         var pressTime = this.mousedownTime.getElapsed();
15692         if(pressTime < 500){
15693             return 400;
15694         }else if(pressTime < 1700){
15695             return 320;
15696         }else if(pressTime < 2600){
15697             return 250;
15698         }else if(pressTime < 3500){
15699             return 180;
15700         }else if(pressTime < 4400){
15701             return 140;
15702         }else if(pressTime < 5300){
15703             return 80;
15704         }else if(pressTime < 6200){
15705             return 50;
15706         }else{
15707             return 10;
15708         }
15709     },
15710
15711     // private
15712     handleMouseOut : function(){
15713         clearTimeout(this.timer);
15714         if(this.pressClass){
15715             this.el.removeClass(this.pressClass);
15716         }
15717         this.el.on("mouseover", this.handleMouseReturn, this);
15718     },
15719
15720     // private
15721     handleMouseReturn : function(){
15722         this.el.un("mouseover", this.handleMouseReturn);
15723         if(this.pressClass){
15724             this.el.addClass(this.pressClass);
15725         }
15726         this.click();
15727     },
15728
15729     // private
15730     handleMouseUp : function(){
15731         clearTimeout(this.timer);
15732         this.el.un("mouseover", this.handleMouseReturn);
15733         this.el.un("mouseout", this.handleMouseOut);
15734         Roo.get(document).un("mouseup", this.handleMouseUp);
15735         this.el.removeClass(this.pressClass);
15736         this.fireEvent("mouseup", this);
15737     }
15738 });/**
15739  * @class Roo.util.Clipboard
15740  * @static
15741  * 
15742  * Clipboard UTILS
15743  * 
15744  **/
15745 Roo.util.Clipboard = {
15746     /**
15747      * Writes a string to the clipboard - using the Clipboard API if https, otherwise using text area.
15748      * @param {String} text to copy to clipboard
15749      */
15750     write : function(text) {
15751         // navigator clipboard api needs a secure context (https)
15752         if (navigator.clipboard && window.isSecureContext) {
15753             // navigator clipboard api method'
15754             navigator.clipboard.writeText(text);
15755             return ;
15756         } 
15757         // text area method
15758         var ta = document.createElement("textarea");
15759         ta.value = text;
15760         // make the textarea out of viewport
15761         ta.style.position = "fixed";
15762         ta.style.left = "-999999px";
15763         ta.style.top = "-999999px";
15764         document.body.appendChild(ta);
15765         ta.focus();
15766         ta.select();
15767         document.execCommand('copy');
15768         (function() {
15769             ta.remove();
15770         }).defer(100);
15771         
15772     }
15773         
15774 }
15775     /*
15776  * Based on:
15777  * Ext JS Library 1.1.1
15778  * Copyright(c) 2006-2007, Ext JS, LLC.
15779  *
15780  * Originally Released Under LGPL - original licence link has changed is not relivant.
15781  *
15782  * Fork - LGPL
15783  * <script type="text/javascript">
15784  */
15785
15786  
15787 /**
15788  * @class Roo.KeyNav
15789  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
15790  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
15791  * way to implement custom navigation schemes for any UI component.</p>
15792  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
15793  * pageUp, pageDown, del, home, end.  Usage:</p>
15794  <pre><code>
15795 var nav = new Roo.KeyNav("my-element", {
15796     "left" : function(e){
15797         this.moveLeft(e.ctrlKey);
15798     },
15799     "right" : function(e){
15800         this.moveRight(e.ctrlKey);
15801     },
15802     "enter" : function(e){
15803         this.save();
15804     },
15805     scope : this
15806 });
15807 </code></pre>
15808  * @constructor
15809  * @param {String/HTMLElement/Roo.Element} el The element to bind to
15810  * @param {Object} config The config
15811  */
15812 Roo.KeyNav = function(el, config){
15813     this.el = Roo.get(el);
15814     Roo.apply(this, config);
15815     if(!this.disabled){
15816         this.disabled = true;
15817         this.enable();
15818     }
15819 };
15820
15821 Roo.KeyNav.prototype = {
15822     /**
15823      * @cfg {Boolean} disabled
15824      * True to disable this KeyNav instance (defaults to false)
15825      */
15826     disabled : false,
15827     /**
15828      * @cfg {String} defaultEventAction
15829      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
15830      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
15831      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
15832      */
15833     defaultEventAction: "stopEvent",
15834     /**
15835      * @cfg {Boolean} forceKeyDown
15836      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
15837      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
15838      * handle keydown instead of keypress.
15839      */
15840     forceKeyDown : false,
15841
15842     // private
15843     prepareEvent : function(e){
15844         var k = e.getKey();
15845         var h = this.keyToHandler[k];
15846         //if(h && this[h]){
15847         //    e.stopPropagation();
15848         //}
15849         if(Roo.isSafari && h && k >= 37 && k <= 40){
15850             e.stopEvent();
15851         }
15852     },
15853
15854     // private
15855     relay : function(e){
15856         var k = e.getKey();
15857         var h = this.keyToHandler[k];
15858         if(h && this[h]){
15859             if(this.doRelay(e, this[h], h) !== true){
15860                 e[this.defaultEventAction]();
15861             }
15862         }
15863     },
15864
15865     // private
15866     doRelay : function(e, h, hname){
15867         return h.call(this.scope || this, e);
15868     },
15869
15870     // possible handlers
15871     enter : false,
15872     left : false,
15873     right : false,
15874     up : false,
15875     down : false,
15876     tab : false,
15877     esc : false,
15878     pageUp : false,
15879     pageDown : false,
15880     del : false,
15881     home : false,
15882     end : false,
15883
15884     // quick lookup hash
15885     keyToHandler : {
15886         37 : "left",
15887         39 : "right",
15888         38 : "up",
15889         40 : "down",
15890         33 : "pageUp",
15891         34 : "pageDown",
15892         46 : "del",
15893         36 : "home",
15894         35 : "end",
15895         13 : "enter",
15896         27 : "esc",
15897         9  : "tab"
15898     },
15899
15900         /**
15901          * Enable this KeyNav
15902          */
15903         enable: function(){
15904                 if(this.disabled){
15905             // ie won't do special keys on keypress, no one else will repeat keys with keydown
15906             // the EventObject will normalize Safari automatically
15907             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
15908                 this.el.on("keydown", this.relay,  this);
15909             }else{
15910                 this.el.on("keydown", this.prepareEvent,  this);
15911                 this.el.on("keypress", this.relay,  this);
15912             }
15913                     this.disabled = false;
15914                 }
15915         },
15916
15917         /**
15918          * Disable this KeyNav
15919          */
15920         disable: function(){
15921                 if(!this.disabled){
15922                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
15923                 this.el.un("keydown", this.relay);
15924             }else{
15925                 this.el.un("keydown", this.prepareEvent);
15926                 this.el.un("keypress", this.relay);
15927             }
15928                     this.disabled = true;
15929                 }
15930         }
15931 };/*
15932  * Based on:
15933  * Ext JS Library 1.1.1
15934  * Copyright(c) 2006-2007, Ext JS, LLC.
15935  *
15936  * Originally Released Under LGPL - original licence link has changed is not relivant.
15937  *
15938  * Fork - LGPL
15939  * <script type="text/javascript">
15940  */
15941
15942  
15943 /**
15944  * @class Roo.KeyMap
15945  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
15946  * The constructor accepts the same config object as defined by {@link #addBinding}.
15947  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
15948  * combination it will call the function with this signature (if the match is a multi-key
15949  * combination the callback will still be called only once): (String key, Roo.EventObject e)
15950  * A KeyMap can also handle a string representation of keys.<br />
15951  * Usage:
15952  <pre><code>
15953 // map one key by key code
15954 var map = new Roo.KeyMap("my-element", {
15955     key: 13, // or Roo.EventObject.ENTER
15956     fn: myHandler,
15957     scope: myObject
15958 });
15959
15960 // map multiple keys to one action by string
15961 var map = new Roo.KeyMap("my-element", {
15962     key: "a\r\n\t",
15963     fn: myHandler,
15964     scope: myObject
15965 });
15966
15967 // map multiple keys to multiple actions by strings and array of codes
15968 var map = new Roo.KeyMap("my-element", [
15969     {
15970         key: [10,13],
15971         fn: function(){ alert("Return was pressed"); }
15972     }, {
15973         key: "abc",
15974         fn: function(){ alert('a, b or c was pressed'); }
15975     }, {
15976         key: "\t",
15977         ctrl:true,
15978         shift:true,
15979         fn: function(){ alert('Control + shift + tab was pressed.'); }
15980     }
15981 ]);
15982 </code></pre>
15983  * <b>Note: A KeyMap starts enabled</b>
15984  * @constructor
15985  * @param {String/HTMLElement/Roo.Element} el The element to bind to
15986  * @param {Object} config The config (see {@link #addBinding})
15987  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
15988  */
15989 Roo.KeyMap = function(el, config, eventName){
15990     this.el  = Roo.get(el);
15991     this.eventName = eventName || "keydown";
15992     this.bindings = [];
15993     if(config){
15994         this.addBinding(config);
15995     }
15996     this.enable();
15997 };
15998
15999 Roo.KeyMap.prototype = {
16000     /**
16001      * True to stop the event from bubbling and prevent the default browser action if the
16002      * key was handled by the KeyMap (defaults to false)
16003      * @type Boolean
16004      */
16005     stopEvent : false,
16006
16007     /**
16008      * Add a new binding to this KeyMap. The following config object properties are supported:
16009      * <pre>
16010 Property    Type             Description
16011 ----------  ---------------  ----------------------------------------------------------------------
16012 key         String/Array     A single keycode or an array of keycodes to handle
16013 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
16014 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
16015 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
16016 fn          Function         The function to call when KeyMap finds the expected key combination
16017 scope       Object           The scope of the callback function
16018 </pre>
16019      *
16020      * Usage:
16021      * <pre><code>
16022 // Create a KeyMap
16023 var map = new Roo.KeyMap(document, {
16024     key: Roo.EventObject.ENTER,
16025     fn: handleKey,
16026     scope: this
16027 });
16028
16029 //Add a new binding to the existing KeyMap later
16030 map.addBinding({
16031     key: 'abc',
16032     shift: true,
16033     fn: handleKey,
16034     scope: this
16035 });
16036 </code></pre>
16037      * @param {Object/Array} config A single KeyMap config or an array of configs
16038      */
16039         addBinding : function(config){
16040         if(config instanceof Array){
16041             for(var i = 0, len = config.length; i < len; i++){
16042                 this.addBinding(config[i]);
16043             }
16044             return;
16045         }
16046         var keyCode = config.key,
16047             shift = config.shift, 
16048             ctrl = config.ctrl, 
16049             alt = config.alt,
16050             fn = config.fn,
16051             scope = config.scope;
16052         if(typeof keyCode == "string"){
16053             var ks = [];
16054             var keyString = keyCode.toUpperCase();
16055             for(var j = 0, len = keyString.length; j < len; j++){
16056                 ks.push(keyString.charCodeAt(j));
16057             }
16058             keyCode = ks;
16059         }
16060         var keyArray = keyCode instanceof Array;
16061         var handler = function(e){
16062             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
16063                 var k = e.getKey();
16064                 if(keyArray){
16065                     for(var i = 0, len = keyCode.length; i < len; i++){
16066                         if(keyCode[i] == k){
16067                           if(this.stopEvent){
16068                               e.stopEvent();
16069                           }
16070                           fn.call(scope || window, k, e);
16071                           return;
16072                         }
16073                     }
16074                 }else{
16075                     if(k == keyCode){
16076                         if(this.stopEvent){
16077                            e.stopEvent();
16078                         }
16079                         fn.call(scope || window, k, e);
16080                     }
16081                 }
16082             }
16083         };
16084         this.bindings.push(handler);  
16085         },
16086
16087     /**
16088      * Shorthand for adding a single key listener
16089      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
16090      * following options:
16091      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
16092      * @param {Function} fn The function to call
16093      * @param {Object} scope (optional) The scope of the function
16094      */
16095     on : function(key, fn, scope){
16096         var keyCode, shift, ctrl, alt;
16097         if(typeof key == "object" && !(key instanceof Array)){
16098             keyCode = key.key;
16099             shift = key.shift;
16100             ctrl = key.ctrl;
16101             alt = key.alt;
16102         }else{
16103             keyCode = key;
16104         }
16105         this.addBinding({
16106             key: keyCode,
16107             shift: shift,
16108             ctrl: ctrl,
16109             alt: alt,
16110             fn: fn,
16111             scope: scope
16112         })
16113     },
16114
16115     // private
16116     handleKeyDown : function(e){
16117             if(this.enabled){ //just in case
16118             var b = this.bindings;
16119             for(var i = 0, len = b.length; i < len; i++){
16120                 b[i].call(this, e);
16121             }
16122             }
16123         },
16124         
16125         /**
16126          * Returns true if this KeyMap is enabled
16127          * @return {Boolean} 
16128          */
16129         isEnabled : function(){
16130             return this.enabled;  
16131         },
16132         
16133         /**
16134          * Enables this KeyMap
16135          */
16136         enable: function(){
16137                 if(!this.enabled){
16138                     this.el.on(this.eventName, this.handleKeyDown, this);
16139                     this.enabled = true;
16140                 }
16141         },
16142
16143         /**
16144          * Disable this KeyMap
16145          */
16146         disable: function(){
16147                 if(this.enabled){
16148                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
16149                     this.enabled = false;
16150                 }
16151         }
16152 };/*
16153  * Based on:
16154  * Ext JS Library 1.1.1
16155  * Copyright(c) 2006-2007, Ext JS, LLC.
16156  *
16157  * Originally Released Under LGPL - original licence link has changed is not relivant.
16158  *
16159  * Fork - LGPL
16160  * <script type="text/javascript">
16161  */
16162
16163  
16164 /**
16165  * @class Roo.util.TextMetrics
16166  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
16167  * wide, in pixels, a given block of text will be.
16168  * @static
16169  */
16170 Roo.util.TextMetrics = function(){
16171     var shared;
16172     return {
16173         /**
16174          * Measures the size of the specified text
16175          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
16176          * that can affect the size of the rendered text
16177          * @param {String} text The text to measure
16178          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
16179          * in order to accurately measure the text height
16180          * @return {Object} An object containing the text's size {width: (width), height: (height)}
16181          */
16182         measure : function(el, text, fixedWidth){
16183             if(!shared){
16184                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
16185             }
16186             shared.bind(el);
16187             shared.setFixedWidth(fixedWidth || 'auto');
16188             return shared.getSize(text);
16189         },
16190
16191         /**
16192          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
16193          * the overhead of multiple calls to initialize the style properties on each measurement.
16194          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
16195          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
16196          * in order to accurately measure the text height
16197          * @return {Roo.util.TextMetrics.Instance} instance The new instance
16198          */
16199         createInstance : function(el, fixedWidth){
16200             return Roo.util.TextMetrics.Instance(el, fixedWidth);
16201         }
16202     };
16203 }();
16204
16205 /**
16206  * @class Roo.util.TextMetrics.Instance
16207  * Instance of  TextMetrics Calcuation
16208  * @constructor
16209  * Create a new TextMetrics Instance
16210  * @param {Object} bindto
16211  * @param {Boolean} fixedWidth
16212  */
16213
16214 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth)
16215 {
16216     var ml = new Roo.Element(document.createElement('div'));
16217     document.body.appendChild(ml.dom);
16218     ml.position('absolute');
16219     ml.setLeftTop(-1000, -1000);
16220     ml.hide();
16221
16222     if(fixedWidth){
16223         ml.setWidth(fixedWidth);
16224     }
16225      
16226     var instance = {
16227         /**
16228          * Returns the size of the specified text based on the internal element's style and width properties
16229          * @param {String} text The text to measure
16230          * @return {Object} An object containing the text's size {width: (width), height: (height)}
16231          */
16232         getSize : function(text){
16233             ml.update(text);
16234             var s = ml.getSize();
16235             ml.update('');
16236             return s;
16237         },
16238
16239         /**
16240          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
16241          * that can affect the size of the rendered text
16242          * @param {String/HTMLElement} el The element, dom node or id
16243          */
16244         bind : function(el){
16245             ml.setStyle(
16246                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
16247             );
16248         },
16249
16250         /**
16251          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
16252          * to set a fixed width in order to accurately measure the text height.
16253          * @param {Number} width The width to set on the element
16254          */
16255         setFixedWidth : function(width){
16256             ml.setWidth(width);
16257         },
16258
16259         /**
16260          * Returns the measured width of the specified text
16261          * @param {String} text The text to measure
16262          * @return {Number} width The width in pixels
16263          */
16264         getWidth : function(text){
16265             ml.dom.style.width = 'auto';
16266             return this.getSize(text).width;
16267         },
16268
16269         /**
16270          * Returns the measured height of the specified text.  For multiline text, be sure to call
16271          * {@link #setFixedWidth} if necessary.
16272          * @param {String} text The text to measure
16273          * @return {Number} height The height in pixels
16274          */
16275         getHeight : function(text){
16276             return this.getSize(text).height;
16277         }
16278     };
16279
16280     instance.bind(bindTo);
16281
16282     return instance;
16283 };
16284
16285 // backwards compat
16286 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
16287  * Based on:
16288  * Ext JS Library 1.1.1
16289  * Copyright(c) 2006-2007, Ext JS, LLC.
16290  *
16291  * Originally Released Under LGPL - original licence link has changed is not relivant.
16292  *
16293  * Fork - LGPL
16294  * <script type="text/javascript">
16295  */
16296
16297 /**
16298  * @class Roo.state.Provider
16299  * Abstract base class for state provider implementations. This class provides methods
16300  * for encoding and decoding <b>typed</b> variables including dates and defines the 
16301  * Provider interface.
16302  */
16303 Roo.state.Provider = function(){
16304     /**
16305      * @event statechange
16306      * Fires when a state change occurs.
16307      * @param {Provider} this This state provider
16308      * @param {String} key The state key which was changed
16309      * @param {String} value The encoded value for the state
16310      */
16311     this.addEvents({
16312         "statechange": true
16313     });
16314     this.state = {};
16315     Roo.state.Provider.superclass.constructor.call(this);
16316 };
16317 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
16318     /**
16319      * Returns the current value for a key
16320      * @param {String} name The key name
16321      * @param {Mixed} defaultValue A default value to return if the key's value is not found
16322      * @return {Mixed} The state data
16323      */
16324     get : function(name, defaultValue){
16325         return typeof this.state[name] == "undefined" ?
16326             defaultValue : this.state[name];
16327     },
16328     
16329     /**
16330      * Clears a value from the state
16331      * @param {String} name The key name
16332      */
16333     clear : function(name){
16334         delete this.state[name];
16335         this.fireEvent("statechange", this, name, null);
16336     },
16337     
16338     /**
16339      * Sets the value for a key
16340      * @param {String} name The key name
16341      * @param {Mixed} value The value to set
16342      */
16343     set : function(name, value){
16344         this.state[name] = value;
16345         this.fireEvent("statechange", this, name, value);
16346     },
16347     
16348     /**
16349      * Decodes a string previously encoded with {@link #encodeValue}.
16350      * @param {String} value The value to decode
16351      * @return {Mixed} The decoded value
16352      */
16353     decodeValue : function(cookie){
16354         var re = /^(a|n|d|b|s|o)\:(.*)$/;
16355         var matches = re.exec(unescape(cookie));
16356         if(!matches || !matches[1]) {
16357             return; // non state cookie
16358         }
16359         var type = matches[1];
16360         var v = matches[2];
16361         switch(type){
16362             case "n":
16363                 return parseFloat(v);
16364             case "d":
16365                 return new Date(Date.parse(v));
16366             case "b":
16367                 return (v == "1");
16368             case "a":
16369                 var all = [];
16370                 var values = v.split("^");
16371                 for(var i = 0, len = values.length; i < len; i++){
16372                     all.push(this.decodeValue(values[i]));
16373                 }
16374                 return all;
16375            case "o":
16376                 var all = {};
16377                 var values = v.split("^");
16378                 for(var i = 0, len = values.length; i < len; i++){
16379                     var kv = values[i].split("=");
16380                     all[kv[0]] = this.decodeValue(kv[1]);
16381                 }
16382                 return all;
16383            default:
16384                 return v;
16385         }
16386     },
16387     
16388     /**
16389      * Encodes a value including type information.  Decode with {@link #decodeValue}.
16390      * @param {Mixed} value The value to encode
16391      * @return {String} The encoded value
16392      */
16393     encodeValue : function(v){
16394         var enc;
16395         if(typeof v == "number"){
16396             enc = "n:" + v;
16397         }else if(typeof v == "boolean"){
16398             enc = "b:" + (v ? "1" : "0");
16399         }else if(v instanceof Date){
16400             enc = "d:" + v.toGMTString();
16401         }else if(v instanceof Array){
16402             var flat = "";
16403             for(var i = 0, len = v.length; i < len; i++){
16404                 flat += this.encodeValue(v[i]);
16405                 if(i != len-1) {
16406                     flat += "^";
16407                 }
16408             }
16409             enc = "a:" + flat;
16410         }else if(typeof v == "object"){
16411             var flat = "";
16412             for(var key in v){
16413                 if(typeof v[key] != "function"){
16414                     flat += key + "=" + this.encodeValue(v[key]) + "^";
16415                 }
16416             }
16417             enc = "o:" + flat.substring(0, flat.length-1);
16418         }else{
16419             enc = "s:" + v;
16420         }
16421         return escape(enc);        
16422     }
16423 });
16424
16425 /*
16426  * Based on:
16427  * Ext JS Library 1.1.1
16428  * Copyright(c) 2006-2007, Ext JS, LLC.
16429  *
16430  * Originally Released Under LGPL - original licence link has changed is not relivant.
16431  *
16432  * Fork - LGPL
16433  * <script type="text/javascript">
16434  */
16435 /**
16436  * @class Roo.state.Manager
16437  * This is the global state manager. By default all components that are "state aware" check this class
16438  * for state information if you don't pass them a custom state provider. In order for this class
16439  * to be useful, it must be initialized with a provider when your application initializes.
16440  <pre><code>
16441 // in your initialization function
16442 init : function(){
16443    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
16444    ...
16445    // supposed you have a {@link Roo.BorderLayout}
16446    var layout = new Roo.BorderLayout(...);
16447    layout.restoreState();
16448    // or a {Roo.BasicDialog}
16449    var dialog = new Roo.BasicDialog(...);
16450    dialog.restoreState();
16451  </code></pre>
16452  * @static
16453  */
16454 Roo.state.Manager = function(){
16455     var provider = new Roo.state.Provider();
16456     
16457     return {
16458         /**
16459          * Configures the default state provider for your application
16460          * @param {Provider} stateProvider The state provider to set
16461          */
16462         setProvider : function(stateProvider){
16463             provider = stateProvider;
16464         },
16465         
16466         /**
16467          * Returns the current value for a key
16468          * @param {String} name The key name
16469          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
16470          * @return {Mixed} The state data
16471          */
16472         get : function(key, defaultValue){
16473             return provider.get(key, defaultValue);
16474         },
16475         
16476         /**
16477          * Sets the value for a key
16478          * @param {String} name The key name
16479          * @param {Mixed} value The state data
16480          */
16481          set : function(key, value){
16482             provider.set(key, value);
16483         },
16484         
16485         /**
16486          * Clears a value from the state
16487          * @param {String} name The key name
16488          */
16489         clear : function(key){
16490             provider.clear(key);
16491         },
16492         
16493         /**
16494          * Gets the currently configured state provider
16495          * @return {Provider} The state provider
16496          */
16497         getProvider : function(){
16498             return provider;
16499         }
16500     };
16501 }();
16502 /*
16503  * Based on:
16504  * Ext JS Library 1.1.1
16505  * Copyright(c) 2006-2007, Ext JS, LLC.
16506  *
16507  * Originally Released Under LGPL - original licence link has changed is not relivant.
16508  *
16509  * Fork - LGPL
16510  * <script type="text/javascript">
16511  */
16512 /**
16513  * @class Roo.state.CookieProvider
16514  * @extends Roo.state.Provider
16515  * The default Provider implementation which saves state via cookies.
16516  * <br />Usage:
16517  <pre><code>
16518    var cp = new Roo.state.CookieProvider({
16519        path: "/cgi-bin/",
16520        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
16521        domain: "roojs.com"
16522    })
16523    Roo.state.Manager.setProvider(cp);
16524  </code></pre>
16525  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
16526  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
16527  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
16528  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
16529  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
16530  * domain the page is running on including the 'www' like 'www.roojs.com')
16531  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
16532  * @constructor
16533  * Create a new CookieProvider
16534  * @param {Object} config The configuration object
16535  */
16536 Roo.state.CookieProvider = function(config){
16537     Roo.state.CookieProvider.superclass.constructor.call(this);
16538     this.path = "/";
16539     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
16540     this.domain = null;
16541     this.secure = false;
16542     Roo.apply(this, config);
16543     this.state = this.readCookies();
16544 };
16545
16546 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
16547     // private
16548     set : function(name, value){
16549         if(typeof value == "undefined" || value === null){
16550             this.clear(name);
16551             return;
16552         }
16553         this.setCookie(name, value);
16554         Roo.state.CookieProvider.superclass.set.call(this, name, value);
16555     },
16556
16557     // private
16558     clear : function(name){
16559         this.clearCookie(name);
16560         Roo.state.CookieProvider.superclass.clear.call(this, name);
16561     },
16562
16563     // private
16564     readCookies : function(){
16565         var cookies = {};
16566         var c = document.cookie + ";";
16567         var re = /\s?(.*?)=(.*?);/g;
16568         var matches;
16569         while((matches = re.exec(c)) != null){
16570             var name = matches[1];
16571             var value = matches[2];
16572             if(name && name.substring(0,3) == "ys-"){
16573                 cookies[name.substr(3)] = this.decodeValue(value);
16574             }
16575         }
16576         return cookies;
16577     },
16578
16579     // private
16580     setCookie : function(name, value){
16581         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
16582            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
16583            ((this.path == null) ? "" : ("; path=" + this.path)) +
16584            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
16585            ((this.secure == true) ? "; secure" : "");
16586     },
16587
16588     // private
16589     clearCookie : function(name){
16590         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
16591            ((this.path == null) ? "" : ("; path=" + this.path)) +
16592            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
16593            ((this.secure == true) ? "; secure" : "");
16594     }
16595 });/*
16596  * Based on:
16597  * Ext JS Library 1.1.1
16598  * Copyright(c) 2006-2007, Ext JS, LLC.
16599  *
16600  * Originally Released Under LGPL - original licence link has changed is not relivant.
16601  *
16602  * Fork - LGPL
16603  * <script type="text/javascript">
16604  */
16605  
16606
16607 /**
16608  * @class Roo.ComponentMgr
16609  * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
16610  * @static
16611  */
16612 Roo.ComponentMgr = function(){
16613     var all = new Roo.util.MixedCollection();
16614
16615     return {
16616         /**
16617          * Registers a component.
16618          * @param {Roo.Component} c The component
16619          */
16620         register : function(c){
16621             all.add(c);
16622         },
16623
16624         /**
16625          * Unregisters a component.
16626          * @param {Roo.Component} c The component
16627          */
16628         unregister : function(c){
16629             all.remove(c);
16630         },
16631
16632         /**
16633          * Returns a component by id
16634          * @param {String} id The component id
16635          */
16636         get : function(id){
16637             return all.get(id);
16638         },
16639
16640         /**
16641          * Registers a function that will be called when a specified component is added to ComponentMgr
16642          * @param {String} id The component id
16643          * @param {Funtction} fn The callback function
16644          * @param {Object} scope The scope of the callback
16645          */
16646         onAvailable : function(id, fn, scope){
16647             all.on("add", function(index, o){
16648                 if(o.id == id){
16649                     fn.call(scope || o, o);
16650                     all.un("add", fn, scope);
16651                 }
16652             });
16653         }
16654     };
16655 }();/*
16656  * Based on:
16657  * Ext JS Library 1.1.1
16658  * Copyright(c) 2006-2007, Ext JS, LLC.
16659  *
16660  * Originally Released Under LGPL - original licence link has changed is not relivant.
16661  *
16662  * Fork - LGPL
16663  * <script type="text/javascript">
16664  */
16665  
16666 /**
16667  * @class Roo.Component
16668  * @extends Roo.util.Observable
16669  * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
16670  * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
16671  * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
16672  * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
16673  * All visual components (widgets) that require rendering into a layout should subclass Component.
16674  * @constructor
16675  * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
16676  * 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
16677  * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
16678  */
16679 Roo.Component = function(config){
16680     config = config || {};
16681     if(config.tagName || config.dom || typeof config == "string"){ // element object
16682         config = {el: config, id: config.id || config};
16683     }
16684     this.initialConfig = config;
16685
16686     Roo.apply(this, config);
16687     this.addEvents({
16688         /**
16689          * @event disable
16690          * Fires after the component is disabled.
16691              * @param {Roo.Component} this
16692              */
16693         disable : true,
16694         /**
16695          * @event enable
16696          * Fires after the component is enabled.
16697              * @param {Roo.Component} this
16698              */
16699         enable : true,
16700         /**
16701          * @event beforeshow
16702          * Fires before the component is shown.  Return false to stop the show.
16703              * @param {Roo.Component} this
16704              */
16705         beforeshow : true,
16706         /**
16707          * @event show
16708          * Fires after the component is shown.
16709              * @param {Roo.Component} this
16710              */
16711         show : true,
16712         /**
16713          * @event beforehide
16714          * Fires before the component is hidden. Return false to stop the hide.
16715              * @param {Roo.Component} this
16716              */
16717         beforehide : true,
16718         /**
16719          * @event hide
16720          * Fires after the component is hidden.
16721              * @param {Roo.Component} this
16722              */
16723         hide : true,
16724         /**
16725          * @event beforerender
16726          * Fires before the component is rendered. Return false to stop the render.
16727              * @param {Roo.Component} this
16728              */
16729         beforerender : true,
16730         /**
16731          * @event render
16732          * Fires after the component is rendered.
16733              * @param {Roo.Component} this
16734              */
16735         render : true,
16736         /**
16737          * @event beforedestroy
16738          * Fires before the component is destroyed. Return false to stop the destroy.
16739              * @param {Roo.Component} this
16740              */
16741         beforedestroy : true,
16742         /**
16743          * @event destroy
16744          * Fires after the component is destroyed.
16745              * @param {Roo.Component} this
16746              */
16747         destroy : true
16748     });
16749     if(!this.id){
16750         this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
16751     }
16752     Roo.ComponentMgr.register(this);
16753     Roo.Component.superclass.constructor.call(this);
16754     this.initComponent();
16755     if(this.renderTo){ // not supported by all components yet. use at your own risk!
16756         this.render(this.renderTo);
16757         delete this.renderTo;
16758     }
16759 };
16760
16761 /** @private */
16762 Roo.Component.AUTO_ID = 1000;
16763
16764 Roo.extend(Roo.Component, Roo.util.Observable, {
16765     /**
16766      * @scope Roo.Component.prototype
16767      * @type {Boolean}
16768      * true if this component is hidden. Read-only.
16769      */
16770     hidden : false,
16771     /**
16772      * @type {Boolean}
16773      * true if this component is disabled. Read-only.
16774      */
16775     disabled : false,
16776     /**
16777      * @type {Boolean}
16778      * true if this component has been rendered. Read-only.
16779      */
16780     rendered : false,
16781     
16782     /** @cfg {String} disableClass
16783      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
16784      */
16785     disabledClass : "x-item-disabled",
16786         /** @cfg {Boolean} allowDomMove
16787          * Whether the component can move the Dom node when rendering (defaults to true).
16788          */
16789     allowDomMove : true,
16790     /** @cfg {String} hideMode (display|visibility)
16791      * How this component should hidden. Supported values are
16792      * "visibility" (css visibility), "offsets" (negative offset position) and
16793      * "display" (css display) - defaults to "display".
16794      */
16795     hideMode: 'display',
16796
16797     /** @private */
16798     ctype : "Roo.Component",
16799
16800     /**
16801      * @cfg {String} actionMode 
16802      * which property holds the element that used for  hide() / show() / disable() / enable()
16803      * default is 'el' for forms you probably want to set this to fieldEl 
16804      */
16805     actionMode : "el",
16806
16807     /** @private */
16808     getActionEl : function(){
16809         return this[this.actionMode];
16810     },
16811
16812     initComponent : Roo.emptyFn,
16813     /**
16814      * If this is a lazy rendering component, render it to its container element.
16815      * @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.
16816      */
16817     render : function(container, position){
16818         
16819         if(this.rendered){
16820             return this;
16821         }
16822         
16823         if(this.fireEvent("beforerender", this) === false){
16824             return false;
16825         }
16826         
16827         if(!container && this.el){
16828             this.el = Roo.get(this.el);
16829             container = this.el.dom.parentNode;
16830             this.allowDomMove = false;
16831         }
16832         this.container = Roo.get(container);
16833         this.rendered = true;
16834         if(position !== undefined){
16835             if(typeof position == 'number'){
16836                 position = this.container.dom.childNodes[position];
16837             }else{
16838                 position = Roo.getDom(position);
16839             }
16840         }
16841         this.onRender(this.container, position || null);
16842         if(this.cls){
16843             this.el.addClass(this.cls);
16844             delete this.cls;
16845         }
16846         if(this.style){
16847             this.el.applyStyles(this.style);
16848             delete this.style;
16849         }
16850         this.fireEvent("render", this);
16851         this.afterRender(this.container);
16852         if(this.hidden){
16853             this.hide();
16854         }
16855         if(this.disabled){
16856             this.disable();
16857         }
16858
16859         return this;
16860         
16861     },
16862
16863     /** @private */
16864     // default function is not really useful
16865     onRender : function(ct, position){
16866         if(this.el){
16867             this.el = Roo.get(this.el);
16868             if(this.allowDomMove !== false){
16869                 ct.dom.insertBefore(this.el.dom, position);
16870             }
16871         }
16872     },
16873
16874     /** @private */
16875     getAutoCreate : function(){
16876         var cfg = typeof this.autoCreate == "object" ?
16877                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
16878         if(this.id && !cfg.id){
16879             cfg.id = this.id;
16880         }
16881         return cfg;
16882     },
16883
16884     /** @private */
16885     afterRender : Roo.emptyFn,
16886
16887     /**
16888      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
16889      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
16890      */
16891     destroy : function(){
16892         if(this.fireEvent("beforedestroy", this) !== false){
16893             this.purgeListeners();
16894             this.beforeDestroy();
16895             if(this.rendered){
16896                 this.el.removeAllListeners();
16897                 this.el.remove();
16898                 if(this.actionMode == "container"){
16899                     this.container.remove();
16900                 }
16901             }
16902             this.onDestroy();
16903             Roo.ComponentMgr.unregister(this);
16904             this.fireEvent("destroy", this);
16905         }
16906     },
16907
16908         /** @private */
16909     beforeDestroy : function(){
16910
16911     },
16912
16913         /** @private */
16914         onDestroy : function(){
16915
16916     },
16917
16918     /**
16919      * Returns the underlying {@link Roo.Element}.
16920      * @return {Roo.Element} The element
16921      */
16922     getEl : function(){
16923         return this.el;
16924     },
16925
16926     /**
16927      * Returns the id of this component.
16928      * @return {String}
16929      */
16930     getId : function(){
16931         return this.id;
16932     },
16933
16934     /**
16935      * Try to focus this component.
16936      * @param {Boolean} selectText True to also select the text in this component (if applicable)
16937      * @return {Roo.Component} this
16938      */
16939     focus : function(selectText){
16940         if(this.rendered){
16941             this.el.focus();
16942             if(selectText === true){
16943                 this.el.dom.select();
16944             }
16945         }
16946         return this;
16947     },
16948
16949     /** @private */
16950     blur : function(){
16951         if(this.rendered){
16952             this.el.blur();
16953         }
16954         return this;
16955     },
16956
16957     /**
16958      * Disable this component.
16959      * @return {Roo.Component} this
16960      */
16961     disable : function(){
16962         if(this.rendered){
16963             this.onDisable();
16964         }
16965         this.disabled = true;
16966         this.fireEvent("disable", this);
16967         return this;
16968     },
16969
16970         // private
16971     onDisable : function(){
16972         this.getActionEl().addClass(this.disabledClass);
16973         this.el.dom.disabled = true;
16974     },
16975
16976     /**
16977      * Enable this component.
16978      * @return {Roo.Component} this
16979      */
16980     enable : function(){
16981         if(this.rendered){
16982             this.onEnable();
16983         }
16984         this.disabled = false;
16985         this.fireEvent("enable", this);
16986         return this;
16987     },
16988
16989         // private
16990     onEnable : function(){
16991         this.getActionEl().removeClass(this.disabledClass);
16992         this.el.dom.disabled = false;
16993     },
16994
16995     /**
16996      * Convenience function for setting disabled/enabled by boolean.
16997      * @param {Boolean} disabled
16998      */
16999     setDisabled : function(disabled){
17000         this[disabled ? "disable" : "enable"]();
17001     },
17002
17003     /**
17004      * Show this component.
17005      * @return {Roo.Component} this
17006      */
17007     show: function(){
17008         if(this.fireEvent("beforeshow", this) !== false){
17009             this.hidden = false;
17010             if(this.rendered){
17011                 this.onShow();
17012             }
17013             this.fireEvent("show", this);
17014         }
17015         return this;
17016     },
17017
17018     // private
17019     onShow : function(){
17020         var ae = this.getActionEl();
17021         if(this.hideMode == 'visibility'){
17022             ae.dom.style.visibility = "visible";
17023         }else if(this.hideMode == 'offsets'){
17024             ae.removeClass('x-hidden');
17025         }else{
17026             ae.dom.style.display = "";
17027         }
17028     },
17029
17030     /**
17031      * Hide this component.
17032      * @return {Roo.Component} this
17033      */
17034     hide: function(){
17035         if(this.fireEvent("beforehide", this) !== false){
17036             this.hidden = true;
17037             if(this.rendered){
17038                 this.onHide();
17039             }
17040             this.fireEvent("hide", this);
17041         }
17042         return this;
17043     },
17044
17045     // private
17046     onHide : function(){
17047         var ae = this.getActionEl();
17048         if(this.hideMode == 'visibility'){
17049             ae.dom.style.visibility = "hidden";
17050         }else if(this.hideMode == 'offsets'){
17051             ae.addClass('x-hidden');
17052         }else{
17053             ae.dom.style.display = "none";
17054         }
17055     },
17056
17057     /**
17058      * Convenience function to hide or show this component by boolean.
17059      * @param {Boolean} visible True to show, false to hide
17060      * @return {Roo.Component} this
17061      */
17062     setVisible: function(visible){
17063         if(visible) {
17064             this.show();
17065         }else{
17066             this.hide();
17067         }
17068         return this;
17069     },
17070
17071     /**
17072      * Returns true if this component is visible.
17073      */
17074     isVisible : function(){
17075         return this.getActionEl().isVisible();
17076     },
17077
17078     cloneConfig : function(overrides){
17079         overrides = overrides || {};
17080         var id = overrides.id || Roo.id();
17081         var cfg = Roo.applyIf(overrides, this.initialConfig);
17082         cfg.id = id; // prevent dup id
17083         return new this.constructor(cfg);
17084     }
17085 });/*
17086  * Based on:
17087  * Ext JS Library 1.1.1
17088  * Copyright(c) 2006-2007, Ext JS, LLC.
17089  *
17090  * Originally Released Under LGPL - original licence link has changed is not relivant.
17091  *
17092  * Fork - LGPL
17093  * <script type="text/javascript">
17094  */
17095
17096 /**
17097  * @class Roo.BoxComponent
17098  * @extends Roo.Component
17099  * Base class for any visual {@link Roo.Component} that uses a box container.  BoxComponent provides automatic box
17100  * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model.  All
17101  * container classes should subclass BoxComponent so that they will work consistently when nested within other Roo
17102  * layout containers.
17103  * @constructor
17104  * @param {Roo.Element/String/Object} config The configuration options.
17105  */
17106 Roo.BoxComponent = function(config){
17107     Roo.Component.call(this, config);
17108     this.addEvents({
17109         /**
17110          * @event resize
17111          * Fires after the component is resized.
17112              * @param {Roo.Component} this
17113              * @param {Number} adjWidth The box-adjusted width that was set
17114              * @param {Number} adjHeight The box-adjusted height that was set
17115              * @param {Number} rawWidth The width that was originally specified
17116              * @param {Number} rawHeight The height that was originally specified
17117              */
17118         resize : true,
17119         /**
17120          * @event move
17121          * Fires after the component is moved.
17122              * @param {Roo.Component} this
17123              * @param {Number} x The new x position
17124              * @param {Number} y The new y position
17125              */
17126         move : true
17127     });
17128 };
17129
17130 Roo.extend(Roo.BoxComponent, Roo.Component, {
17131     // private, set in afterRender to signify that the component has been rendered
17132     boxReady : false,
17133     // private, used to defer height settings to subclasses
17134     deferHeight: false,
17135     /** @cfg {Number} width
17136      * width (optional) size of component
17137      */
17138      /** @cfg {Number} height
17139      * height (optional) size of component
17140      */
17141      
17142     /**
17143      * Sets the width and height of the component.  This method fires the resize event.  This method can accept
17144      * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
17145      * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
17146      * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
17147      * @return {Roo.BoxComponent} this
17148      */
17149     setSize : function(w, h){
17150         // support for standard size objects
17151         if(typeof w == 'object'){
17152             h = w.height;
17153             w = w.width;
17154         }
17155         // not rendered
17156         if(!this.boxReady){
17157             this.width = w;
17158             this.height = h;
17159             return this;
17160         }
17161
17162         // prevent recalcs when not needed
17163         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
17164             return this;
17165         }
17166         this.lastSize = {width: w, height: h};
17167
17168         var adj = this.adjustSize(w, h);
17169         var aw = adj.width, ah = adj.height;
17170         if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
17171             var rz = this.getResizeEl();
17172             if(!this.deferHeight && aw !== undefined && ah !== undefined){
17173                 rz.setSize(aw, ah);
17174             }else if(!this.deferHeight && ah !== undefined){
17175                 rz.setHeight(ah);
17176             }else if(aw !== undefined){
17177                 rz.setWidth(aw);
17178             }
17179             this.onResize(aw, ah, w, h);
17180             this.fireEvent('resize', this, aw, ah, w, h);
17181         }
17182         return this;
17183     },
17184
17185     /**
17186      * Gets the current size of the component's underlying element.
17187      * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
17188      */
17189     getSize : function(){
17190         return this.el.getSize();
17191     },
17192
17193     /**
17194      * Gets the current XY position of the component's underlying element.
17195      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
17196      * @return {Array} The XY position of the element (e.g., [100, 200])
17197      */
17198     getPosition : function(local){
17199         if(local === true){
17200             return [this.el.getLeft(true), this.el.getTop(true)];
17201         }
17202         return this.xy || this.el.getXY();
17203     },
17204
17205     /**
17206      * Gets the current box measurements of the component's underlying element.
17207      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
17208      * @returns {Object} box An object in the format {x, y, width, height}
17209      */
17210     getBox : function(local){
17211         var s = this.el.getSize();
17212         if(local){
17213             s.x = this.el.getLeft(true);
17214             s.y = this.el.getTop(true);
17215         }else{
17216             var xy = this.xy || this.el.getXY();
17217             s.x = xy[0];
17218             s.y = xy[1];
17219         }
17220         return s;
17221     },
17222
17223     /**
17224      * Sets the current box measurements of the component's underlying element.
17225      * @param {Object} box An object in the format {x, y, width, height}
17226      * @returns {Roo.BoxComponent} this
17227      */
17228     updateBox : function(box){
17229         this.setSize(box.width, box.height);
17230         this.setPagePosition(box.x, box.y);
17231         return this;
17232     },
17233
17234     // protected
17235     getResizeEl : function(){
17236         return this.resizeEl || this.el;
17237     },
17238
17239     // protected
17240     getPositionEl : function(){
17241         return this.positionEl || this.el;
17242     },
17243
17244     /**
17245      * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
17246      * This method fires the move event.
17247      * @param {Number} left The new left
17248      * @param {Number} top The new top
17249      * @returns {Roo.BoxComponent} this
17250      */
17251     setPosition : function(x, y){
17252         this.x = x;
17253         this.y = y;
17254         if(!this.boxReady){
17255             return this;
17256         }
17257         var adj = this.adjustPosition(x, y);
17258         var ax = adj.x, ay = adj.y;
17259
17260         var el = this.getPositionEl();
17261         if(ax !== undefined || ay !== undefined){
17262             if(ax !== undefined && ay !== undefined){
17263                 el.setLeftTop(ax, ay);
17264             }else if(ax !== undefined){
17265                 el.setLeft(ax);
17266             }else if(ay !== undefined){
17267                 el.setTop(ay);
17268             }
17269             this.onPosition(ax, ay);
17270             this.fireEvent('move', this, ax, ay);
17271         }
17272         return this;
17273     },
17274
17275     /**
17276      * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
17277      * This method fires the move event.
17278      * @param {Number} x The new x position
17279      * @param {Number} y The new y position
17280      * @returns {Roo.BoxComponent} this
17281      */
17282     setPagePosition : function(x, y){
17283         this.pageX = x;
17284         this.pageY = y;
17285         if(!this.boxReady){
17286             return;
17287         }
17288         if(x === undefined || y === undefined){ // cannot translate undefined points
17289             return;
17290         }
17291         var p = this.el.translatePoints(x, y);
17292         this.setPosition(p.left, p.top);
17293         return this;
17294     },
17295
17296     // private
17297     onRender : function(ct, position){
17298         Roo.BoxComponent.superclass.onRender.call(this, ct, position);
17299         if(this.resizeEl){
17300             this.resizeEl = Roo.get(this.resizeEl);
17301         }
17302         if(this.positionEl){
17303             this.positionEl = Roo.get(this.positionEl);
17304         }
17305     },
17306
17307     // private
17308     afterRender : function(){
17309         Roo.BoxComponent.superclass.afterRender.call(this);
17310         this.boxReady = true;
17311         this.setSize(this.width, this.height);
17312         if(this.x || this.y){
17313             this.setPosition(this.x, this.y);
17314         }
17315         if(this.pageX || this.pageY){
17316             this.setPagePosition(this.pageX, this.pageY);
17317         }
17318     },
17319
17320     /**
17321      * Force the component's size to recalculate based on the underlying element's current height and width.
17322      * @returns {Roo.BoxComponent} this
17323      */
17324     syncSize : function(){
17325         delete this.lastSize;
17326         this.setSize(this.el.getWidth(), this.el.getHeight());
17327         return this;
17328     },
17329
17330     /**
17331      * Called after the component is resized, this method is empty by default but can be implemented by any
17332      * subclass that needs to perform custom logic after a resize occurs.
17333      * @param {Number} adjWidth The box-adjusted width that was set
17334      * @param {Number} adjHeight The box-adjusted height that was set
17335      * @param {Number} rawWidth The width that was originally specified
17336      * @param {Number} rawHeight The height that was originally specified
17337      */
17338     onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
17339
17340     },
17341
17342     /**
17343      * Called after the component is moved, this method is empty by default but can be implemented by any
17344      * subclass that needs to perform custom logic after a move occurs.
17345      * @param {Number} x The new x position
17346      * @param {Number} y The new y position
17347      */
17348     onPosition : function(x, y){
17349
17350     },
17351
17352     // private
17353     adjustSize : function(w, h){
17354         if(this.autoWidth){
17355             w = 'auto';
17356         }
17357         if(this.autoHeight){
17358             h = 'auto';
17359         }
17360         return {width : w, height: h};
17361     },
17362
17363     // private
17364     adjustPosition : function(x, y){
17365         return {x : x, y: y};
17366     }
17367 });/*
17368  * Based on:
17369  * Ext JS Library 1.1.1
17370  * Copyright(c) 2006-2007, Ext JS, LLC.
17371  *
17372  * Originally Released Under LGPL - original licence link has changed is not relivant.
17373  *
17374  * Fork - LGPL
17375  * <script type="text/javascript">
17376  */
17377  (function(){ 
17378 /**
17379  * @class Roo.Layer
17380  * @extends Roo.Element
17381  * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
17382  * automatic maintaining of shadow/shim positions.
17383  * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
17384  * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
17385  * you can pass a string with a CSS class name. False turns off the shadow.
17386  * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
17387  * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
17388  * @cfg {String} cls CSS class to add to the element
17389  * @cfg {Number} zindex Starting z-index (defaults to 11000)
17390  * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
17391  * @constructor
17392  * @param {Object} config An object with config options.
17393  * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
17394  */
17395
17396 Roo.Layer = function(config, existingEl){
17397     config = config || {};
17398     var dh = Roo.DomHelper;
17399     var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
17400     if(existingEl){
17401         this.dom = Roo.getDom(existingEl);
17402     }
17403     if(!this.dom){
17404         var o = config.dh || {tag: "div", cls: "x-layer"};
17405         this.dom = dh.append(pel, o);
17406     }
17407     if(config.cls){
17408         this.addClass(config.cls);
17409     }
17410     this.constrain = config.constrain !== false;
17411     this.visibilityMode = Roo.Element.VISIBILITY;
17412     if(config.id){
17413         this.id = this.dom.id = config.id;
17414     }else{
17415         this.id = Roo.id(this.dom);
17416     }
17417     this.zindex = config.zindex || this.getZIndex();
17418     this.position("absolute", this.zindex);
17419     if(config.shadow){
17420         this.shadowOffset = config.shadowOffset || 4;
17421         this.shadow = new Roo.Shadow({
17422             offset : this.shadowOffset,
17423             mode : config.shadow
17424         });
17425     }else{
17426         this.shadowOffset = 0;
17427     }
17428     this.useShim = config.shim !== false && Roo.useShims;
17429     this.useDisplay = config.useDisplay;
17430     this.hide();
17431 };
17432
17433 var supr = Roo.Element.prototype;
17434
17435 // shims are shared among layer to keep from having 100 iframes
17436 var shims = [];
17437
17438 Roo.extend(Roo.Layer, Roo.Element, {
17439
17440     getZIndex : function(){
17441         return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
17442     },
17443
17444     getShim : function(){
17445         if(!this.useShim){
17446             return null;
17447         }
17448         if(this.shim){
17449             return this.shim;
17450         }
17451         var shim = shims.shift();
17452         if(!shim){
17453             shim = this.createShim();
17454             shim.enableDisplayMode('block');
17455             shim.dom.style.display = 'none';
17456             shim.dom.style.visibility = 'visible';
17457         }
17458         var pn = this.dom.parentNode;
17459         if(shim.dom.parentNode != pn){
17460             pn.insertBefore(shim.dom, this.dom);
17461         }
17462         shim.setStyle('z-index', this.getZIndex()-2);
17463         this.shim = shim;
17464         return shim;
17465     },
17466
17467     hideShim : function(){
17468         if(this.shim){
17469             this.shim.setDisplayed(false);
17470             shims.push(this.shim);
17471             delete this.shim;
17472         }
17473     },
17474
17475     disableShadow : function(){
17476         if(this.shadow){
17477             this.shadowDisabled = true;
17478             this.shadow.hide();
17479             this.lastShadowOffset = this.shadowOffset;
17480             this.shadowOffset = 0;
17481         }
17482     },
17483
17484     enableShadow : function(show){
17485         if(this.shadow){
17486             this.shadowDisabled = false;
17487             this.shadowOffset = this.lastShadowOffset;
17488             delete this.lastShadowOffset;
17489             if(show){
17490                 this.sync(true);
17491             }
17492         }
17493     },
17494
17495     // private
17496     // this code can execute repeatedly in milliseconds (i.e. during a drag) so
17497     // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
17498     sync : function(doShow){
17499         var sw = this.shadow;
17500         if(!this.updating && this.isVisible() && (sw || this.useShim)){
17501             var sh = this.getShim();
17502
17503             var w = this.getWidth(),
17504                 h = this.getHeight();
17505
17506             var l = this.getLeft(true),
17507                 t = this.getTop(true);
17508
17509             if(sw && !this.shadowDisabled){
17510                 if(doShow && !sw.isVisible()){
17511                     sw.show(this);
17512                 }else{
17513                     sw.realign(l, t, w, h);
17514                 }
17515                 if(sh){
17516                     if(doShow){
17517                        sh.show();
17518                     }
17519                     // fit the shim behind the shadow, so it is shimmed too
17520                     var a = sw.adjusts, s = sh.dom.style;
17521                     s.left = (Math.min(l, l+a.l))+"px";
17522                     s.top = (Math.min(t, t+a.t))+"px";
17523                     s.width = (w+a.w)+"px";
17524                     s.height = (h+a.h)+"px";
17525                 }
17526             }else if(sh){
17527                 if(doShow){
17528                    sh.show();
17529                 }
17530                 sh.setSize(w, h);
17531                 sh.setLeftTop(l, t);
17532             }
17533             
17534         }
17535     },
17536
17537     // private
17538     destroy : function(){
17539         this.hideShim();
17540         if(this.shadow){
17541             this.shadow.hide();
17542         }
17543         this.removeAllListeners();
17544         var pn = this.dom.parentNode;
17545         if(pn){
17546             pn.removeChild(this.dom);
17547         }
17548         Roo.Element.uncache(this.id);
17549     },
17550
17551     remove : function(){
17552         this.destroy();
17553     },
17554
17555     // private
17556     beginUpdate : function(){
17557         this.updating = true;
17558     },
17559
17560     // private
17561     endUpdate : function(){
17562         this.updating = false;
17563         this.sync(true);
17564     },
17565
17566     // private
17567     hideUnders : function(negOffset){
17568         if(this.shadow){
17569             this.shadow.hide();
17570         }
17571         this.hideShim();
17572     },
17573
17574     // private
17575     constrainXY : function(){
17576         if(this.constrain){
17577             var vw = Roo.lib.Dom.getViewWidth(),
17578                 vh = Roo.lib.Dom.getViewHeight();
17579             var s = Roo.get(document).getScroll();
17580
17581             var xy = this.getXY();
17582             var x = xy[0], y = xy[1];   
17583             var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
17584             // only move it if it needs it
17585             var moved = false;
17586             // first validate right/bottom
17587             if((x + w) > vw+s.left){
17588                 x = vw - w - this.shadowOffset;
17589                 moved = true;
17590             }
17591             if((y + h) > vh+s.top){
17592                 y = vh - h - this.shadowOffset;
17593                 moved = true;
17594             }
17595             // then make sure top/left isn't negative
17596             if(x < s.left){
17597                 x = s.left;
17598                 moved = true;
17599             }
17600             if(y < s.top){
17601                 y = s.top;
17602                 moved = true;
17603             }
17604             if(moved){
17605                 if(this.avoidY){
17606                     var ay = this.avoidY;
17607                     if(y <= ay && (y+h) >= ay){
17608                         y = ay-h-5;   
17609                     }
17610                 }
17611                 xy = [x, y];
17612                 this.storeXY(xy);
17613                 supr.setXY.call(this, xy);
17614                 this.sync();
17615             }
17616         }
17617     },
17618
17619     isVisible : function(){
17620         return this.visible;    
17621     },
17622
17623     // private
17624     showAction : function(){
17625         this.visible = true; // track visibility to prevent getStyle calls
17626         if(this.useDisplay === true){
17627             this.setDisplayed("");
17628         }else if(this.lastXY){
17629             supr.setXY.call(this, this.lastXY);
17630         }else if(this.lastLT){
17631             supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
17632         }
17633     },
17634
17635     // private
17636     hideAction : function(){
17637         this.visible = false;
17638         if(this.useDisplay === true){
17639             this.setDisplayed(false);
17640         }else{
17641             this.setLeftTop(-10000,-10000);
17642         }
17643     },
17644
17645     // overridden Element method
17646     setVisible : function(v, a, d, c, e){
17647         if(v){
17648             this.showAction();
17649         }
17650         if(a && v){
17651             var cb = function(){
17652                 this.sync(true);
17653                 if(c){
17654                     c();
17655                 }
17656             }.createDelegate(this);
17657             supr.setVisible.call(this, true, true, d, cb, e);
17658         }else{
17659             if(!v){
17660                 this.hideUnders(true);
17661             }
17662             var cb = c;
17663             if(a){
17664                 cb = function(){
17665                     this.hideAction();
17666                     if(c){
17667                         c();
17668                     }
17669                 }.createDelegate(this);
17670             }
17671             supr.setVisible.call(this, v, a, d, cb, e);
17672             if(v){
17673                 this.sync(true);
17674             }else if(!a){
17675                 this.hideAction();
17676             }
17677         }
17678     },
17679
17680     storeXY : function(xy){
17681         delete this.lastLT;
17682         this.lastXY = xy;
17683     },
17684
17685     storeLeftTop : function(left, top){
17686         delete this.lastXY;
17687         this.lastLT = [left, top];
17688     },
17689
17690     // private
17691     beforeFx : function(){
17692         this.beforeAction();
17693         return Roo.Layer.superclass.beforeFx.apply(this, arguments);
17694     },
17695
17696     // private
17697     afterFx : function(){
17698         Roo.Layer.superclass.afterFx.apply(this, arguments);
17699         this.sync(this.isVisible());
17700     },
17701
17702     // private
17703     beforeAction : function(){
17704         if(!this.updating && this.shadow){
17705             this.shadow.hide();
17706         }
17707     },
17708
17709     // overridden Element method
17710     setLeft : function(left){
17711         this.storeLeftTop(left, this.getTop(true));
17712         supr.setLeft.apply(this, arguments);
17713         this.sync();
17714     },
17715
17716     setTop : function(top){
17717         this.storeLeftTop(this.getLeft(true), top);
17718         supr.setTop.apply(this, arguments);
17719         this.sync();
17720     },
17721
17722     setLeftTop : function(left, top){
17723         this.storeLeftTop(left, top);
17724         supr.setLeftTop.apply(this, arguments);
17725         this.sync();
17726     },
17727
17728     setXY : function(xy, a, d, c, e){
17729         this.fixDisplay();
17730         this.beforeAction();
17731         this.storeXY(xy);
17732         var cb = this.createCB(c);
17733         supr.setXY.call(this, xy, a, d, cb, e);
17734         if(!a){
17735             cb();
17736         }
17737     },
17738
17739     // private
17740     createCB : function(c){
17741         var el = this;
17742         return function(){
17743             el.constrainXY();
17744             el.sync(true);
17745             if(c){
17746                 c();
17747             }
17748         };
17749     },
17750
17751     // overridden Element method
17752     setX : function(x, a, d, c, e){
17753         this.setXY([x, this.getY()], a, d, c, e);
17754     },
17755
17756     // overridden Element method
17757     setY : function(y, a, d, c, e){
17758         this.setXY([this.getX(), y], a, d, c, e);
17759     },
17760
17761     // overridden Element method
17762     setSize : function(w, h, a, d, c, e){
17763         this.beforeAction();
17764         var cb = this.createCB(c);
17765         supr.setSize.call(this, w, h, a, d, cb, e);
17766         if(!a){
17767             cb();
17768         }
17769     },
17770
17771     // overridden Element method
17772     setWidth : function(w, a, d, c, e){
17773         this.beforeAction();
17774         var cb = this.createCB(c);
17775         supr.setWidth.call(this, w, a, d, cb, e);
17776         if(!a){
17777             cb();
17778         }
17779     },
17780
17781     // overridden Element method
17782     setHeight : function(h, a, d, c, e){
17783         this.beforeAction();
17784         var cb = this.createCB(c);
17785         supr.setHeight.call(this, h, a, d, cb, e);
17786         if(!a){
17787             cb();
17788         }
17789     },
17790
17791     // overridden Element method
17792     setBounds : function(x, y, w, h, a, d, c, e){
17793         this.beforeAction();
17794         var cb = this.createCB(c);
17795         if(!a){
17796             this.storeXY([x, y]);
17797             supr.setXY.call(this, [x, y]);
17798             supr.setSize.call(this, w, h, a, d, cb, e);
17799             cb();
17800         }else{
17801             supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
17802         }
17803         return this;
17804     },
17805     
17806     /**
17807      * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
17808      * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
17809      * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
17810      * @param {Number} zindex The new z-index to set
17811      * @return {this} The Layer
17812      */
17813     setZIndex : function(zindex){
17814         this.zindex = zindex;
17815         this.setStyle("z-index", zindex + 2);
17816         if(this.shadow){
17817             this.shadow.setZIndex(zindex + 1);
17818         }
17819         if(this.shim){
17820             this.shim.setStyle("z-index", zindex);
17821         }
17822     }
17823 });
17824 })();/*
17825  * Original code for Roojs - LGPL
17826  * <script type="text/javascript">
17827  */
17828  
17829 /**
17830  * @class Roo.XComponent
17831  * A delayed Element creator...
17832  * Or a way to group chunks of interface together.
17833  * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
17834  *  used in conjunction with XComponent.build() it will create an instance of each element,
17835  *  then call addxtype() to build the User interface.
17836  * 
17837  * Mypart.xyx = new Roo.XComponent({
17838
17839     parent : 'Mypart.xyz', // empty == document.element.!!
17840     order : '001',
17841     name : 'xxxx'
17842     region : 'xxxx'
17843     disabled : function() {} 
17844      
17845     tree : function() { // return an tree of xtype declared components
17846         var MODULE = this;
17847         return 
17848         {
17849             xtype : 'NestedLayoutPanel',
17850             // technicall
17851         }
17852      ]
17853  *})
17854  *
17855  *
17856  * It can be used to build a big heiracy, with parent etc.
17857  * or you can just use this to render a single compoent to a dom element
17858  * MYPART.render(Roo.Element | String(id) | dom_element )
17859  *
17860  *
17861  * Usage patterns.
17862  *
17863  * Classic Roo
17864  *
17865  * Roo is designed primarily as a single page application, so the UI build for a standard interface will
17866  * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
17867  *
17868  * Each sub module is expected to have a parent pointing to the class name of it's parent module.
17869  *
17870  * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
17871  * - if mulitple topModules exist, the last one is defined as the top module.
17872  *
17873  * Embeded Roo
17874  * 
17875  * When the top level or multiple modules are to embedded into a existing HTML page,
17876  * the parent element can container '#id' of the element where the module will be drawn.
17877  *
17878  * Bootstrap Roo
17879  *
17880  * Unlike classic Roo, the bootstrap tends not to be used as a single page.
17881  * it relies more on a include mechanism, where sub modules are included into an outer page.
17882  * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
17883  * 
17884  * Bootstrap Roo Included elements
17885  *
17886  * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
17887  * hence confusing the component builder as it thinks there are multiple top level elements. 
17888  *
17889  * String Over-ride & Translations
17890  *
17891  * Our builder application writes all the strings as _strings and _named_strings. This is to enable the translation of elements,
17892  * and also the 'overlaying of string values - needed when different versions of the same application with different text content
17893  * are needed. @see Roo.XComponent.overlayString  
17894  * 
17895  * 
17896  * 
17897  * @extends Roo.util.Observable
17898  * @constructor
17899  * @param cfg {Object} configuration of component
17900  * 
17901  */
17902 Roo.XComponent = function(cfg) {
17903     Roo.apply(this, cfg);
17904     this.addEvents({ 
17905         /**
17906              * @event built
17907              * Fires when this the componnt is built
17908              * @param {Roo.XComponent} c the component
17909              */
17910         'built' : true
17911         
17912     });
17913     this.region = this.region || 'center'; // default..
17914     Roo.XComponent.register(this);
17915     this.modules = false;
17916     this.el = false; // where the layout goes..
17917     
17918     
17919 }
17920 Roo.extend(Roo.XComponent, Roo.util.Observable, {
17921     /**
17922      * @property el
17923      * The created element (with Roo.factory())
17924      * @type {Roo.Layout}
17925      */
17926     el  : false,
17927     
17928     /**
17929      * @property el
17930      * for BC  - use el in new code
17931      * @type {Roo.Layout}
17932      */
17933     panel : false,
17934     
17935     /**
17936      * @property layout
17937      * for BC  - use el in new code
17938      * @type {Roo.Layout}
17939      */
17940     layout : false,
17941     
17942      /**
17943      * @cfg {Function|boolean} disabled
17944      * If this module is disabled by some rule, return true from the funtion
17945      */
17946     disabled : false,
17947     
17948     /**
17949      * @cfg {String} parent 
17950      * Name of parent element which it get xtype added to..
17951      */
17952     parent: false,
17953     
17954     /**
17955      * @cfg {String} order
17956      * Used to set the order in which elements are created (usefull for multiple tabs)
17957      */
17958     
17959     order : false,
17960     /**
17961      * @cfg {String} name
17962      * String to display while loading.
17963      */
17964     name : false,
17965     /**
17966      * @cfg {String} region
17967      * Region to render component to (defaults to center)
17968      */
17969     region : 'center',
17970     
17971     /**
17972      * @cfg {Array} items
17973      * A single item array - the first element is the root of the tree..
17974      * It's done this way to stay compatible with the Xtype system...
17975      */
17976     items : false,
17977     
17978     /**
17979      * @property _tree
17980      * The method that retuns the tree of parts that make up this compoennt 
17981      * @type {function}
17982      */
17983     _tree  : false,
17984     
17985      /**
17986      * render
17987      * render element to dom or tree
17988      * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
17989      */
17990     
17991     render : function(el)
17992     {
17993         
17994         el = el || false;
17995         var hp = this.parent ? 1 : 0;
17996         Roo.debug &&  Roo.log(this);
17997         
17998         var tree = this._tree ? this._tree() : this.tree();
17999
18000         
18001         if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
18002             // if parent is a '#.....' string, then let's use that..
18003             var ename = this.parent.substr(1);
18004             this.parent = false;
18005             Roo.debug && Roo.log(ename);
18006             switch (ename) {
18007                 case 'bootstrap-body':
18008                     if (typeof(tree.el) != 'undefined' && tree.el == document.body)  {
18009                         // this is the BorderLayout standard?
18010                        this.parent = { el : true };
18011                        break;
18012                     }
18013                     if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype)  > -1)  {
18014                         // need to insert stuff...
18015                         this.parent =  {
18016                              el : new Roo.bootstrap.layout.Border({
18017                                  el : document.body, 
18018                      
18019                                  center: {
18020                                     titlebar: false,
18021                                     autoScroll:false,
18022                                     closeOnTab: true,
18023                                     tabPosition: 'top',
18024                                       //resizeTabs: true,
18025                                     alwaysShowTabs: true,
18026                                     hideTabs: false
18027                                      //minTabWidth: 140
18028                                  }
18029                              })
18030                         
18031                          };
18032                          break;
18033                     }
18034                          
18035                     if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
18036                         this.parent = { el :  new  Roo.bootstrap.Body() };
18037                         Roo.debug && Roo.log("setting el to doc body");
18038                          
18039                     } else {
18040                         throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
18041                     }
18042                     break;
18043                 case 'bootstrap':
18044                     this.parent = { el : true};
18045                     // fall through
18046                 default:
18047                     el = Roo.get(ename);
18048                     if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
18049                         this.parent = { el : true};
18050                     }
18051                     
18052                     break;
18053             }
18054                 
18055             
18056             if (!el && !this.parent) {
18057                 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
18058                 return;
18059             }
18060         }
18061         
18062         Roo.debug && Roo.log("EL:");
18063         Roo.debug && Roo.log(el);
18064         Roo.debug && Roo.log("this.parent.el:");
18065         Roo.debug && Roo.log(this.parent.el);
18066         
18067
18068         // altertive root elements ??? - we need a better way to indicate these.
18069         var is_alt = Roo.XComponent.is_alt ||
18070                     (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
18071                     (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
18072                     (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
18073         
18074         
18075         
18076         if (!this.parent && is_alt) {
18077             //el = Roo.get(document.body);
18078             this.parent = { el : true };
18079         }
18080             
18081             
18082         
18083         if (!this.parent) {
18084             
18085             Roo.debug && Roo.log("no parent - creating one");
18086             
18087             el = el ? Roo.get(el) : false;      
18088             
18089             if (typeof(Roo.BorderLayout) == 'undefined' ) {
18090                 
18091                 this.parent =  {
18092                     el : new Roo.bootstrap.layout.Border({
18093                         el: el || document.body,
18094                     
18095                         center: {
18096                             titlebar: false,
18097                             autoScroll:false,
18098                             closeOnTab: true,
18099                             tabPosition: 'top',
18100                              //resizeTabs: true,
18101                             alwaysShowTabs: false,
18102                             hideTabs: true,
18103                             minTabWidth: 140,
18104                             overflow: 'visible'
18105                          }
18106                      })
18107                 };
18108             } else {
18109             
18110                 // it's a top level one..
18111                 this.parent =  {
18112                     el : new Roo.BorderLayout(el || document.body, {
18113                         center: {
18114                             titlebar: false,
18115                             autoScroll:false,
18116                             closeOnTab: true,
18117                             tabPosition: 'top',
18118                              //resizeTabs: true,
18119                             alwaysShowTabs: el && hp? false :  true,
18120                             hideTabs: el || !hp ? true :  false,
18121                             minTabWidth: 140
18122                          }
18123                     })
18124                 };
18125             }
18126         }
18127         
18128         if (!this.parent.el) {
18129                 // probably an old style ctor, which has been disabled.
18130                 return;
18131
18132         }
18133                 // The 'tree' method is  '_tree now' 
18134             
18135         tree.region = tree.region || this.region;
18136         var is_body = false;
18137         if (this.parent.el === true) {
18138             // bootstrap... - body..
18139             if (el) {
18140                 tree.el = el;
18141             }
18142             this.parent.el = Roo.factory(tree);
18143             is_body = true;
18144         }
18145         
18146         this.el = this.parent.el.addxtype(tree, undefined, is_body);
18147         this.fireEvent('built', this);
18148         
18149         this.panel = this.el;
18150         this.layout = this.panel.layout;
18151         this.parentLayout = this.parent.layout  || false;  
18152          
18153     }
18154     
18155 });
18156
18157 Roo.apply(Roo.XComponent, {
18158     /**
18159      * @property  hideProgress
18160      * true to disable the building progress bar.. usefull on single page renders.
18161      * @type Boolean
18162      */
18163     hideProgress : false,
18164     /**
18165      * @property  buildCompleted
18166      * True when the builder has completed building the interface.
18167      * @type Boolean
18168      */
18169     buildCompleted : false,
18170      
18171     /**
18172      * @property  topModule
18173      * the upper most module - uses document.element as it's constructor.
18174      * @type Object
18175      */
18176      
18177     topModule  : false,
18178       
18179     /**
18180      * @property  modules
18181      * array of modules to be created by registration system.
18182      * @type {Array} of Roo.XComponent
18183      */
18184     
18185     modules : [],
18186     /**
18187      * @property  elmodules
18188      * array of modules to be created by which use #ID 
18189      * @type {Array} of Roo.XComponent
18190      */
18191      
18192     elmodules : [],
18193
18194      /**
18195      * @property  is_alt
18196      * Is an alternative Root - normally used by bootstrap or other systems,
18197      *    where the top element in the tree can wrap 'body' 
18198      * @type {boolean}  (default false)
18199      */
18200      
18201     is_alt : false,
18202     /**
18203      * @property  build_from_html
18204      * Build elements from html - used by bootstrap HTML stuff 
18205      *    - this is cleared after build is completed
18206      * @type {boolean}    (default false)
18207      */
18208      
18209     build_from_html : false,
18210     /**
18211      * Register components to be built later.
18212      *
18213      * This solves the following issues
18214      * - Building is not done on page load, but after an authentication process has occured.
18215      * - Interface elements are registered on page load
18216      * - Parent Interface elements may not be loaded before child, so this handles that..
18217      * 
18218      *
18219      * example:
18220      * 
18221      * MyApp.register({
18222           order : '000001',
18223           module : 'Pman.Tab.projectMgr',
18224           region : 'center',
18225           parent : 'Pman.layout',
18226           disabled : false,  // or use a function..
18227         })
18228      
18229      * * @param {Object} details about module
18230      */
18231     register : function(obj) {
18232                 
18233         Roo.XComponent.event.fireEvent('register', obj);
18234         switch(typeof(obj.disabled) ) {
18235                 
18236             case 'undefined':
18237                 break;
18238             
18239             case 'function':
18240                 if ( obj.disabled() ) {
18241                         return;
18242                 }
18243                 break;
18244             
18245             default:
18246                 if (obj.disabled || obj.region == '#disabled') {
18247                         return;
18248                 }
18249                 break;
18250         }
18251                 
18252         this.modules.push(obj);
18253          
18254     },
18255     /**
18256      * convert a string to an object..
18257      * eg. 'AAA.BBB' -> finds AAA.BBB
18258
18259      */
18260     
18261     toObject : function(str)
18262     {
18263         if (!str || typeof(str) == 'object') {
18264             return str;
18265         }
18266         if (str.substring(0,1) == '#') {
18267             return str;
18268         }
18269
18270         var ar = str.split('.');
18271         var rt, o;
18272         rt = ar.shift();
18273             /** eval:var:o */
18274         try {
18275             eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
18276         } catch (e) {
18277             throw "Module not found : " + str;
18278         }
18279         
18280         if (o === false) {
18281             throw "Module not found : " + str;
18282         }
18283         Roo.each(ar, function(e) {
18284             if (typeof(o[e]) == 'undefined') {
18285                 throw "Module not found : " + str;
18286             }
18287             o = o[e];
18288         });
18289         
18290         return o;
18291         
18292     },
18293     
18294     
18295     /**
18296      * move modules into their correct place in the tree..
18297      * 
18298      */
18299     preBuild : function ()
18300     {
18301         var _t = this;
18302         Roo.each(this.modules , function (obj)
18303         {
18304             Roo.XComponent.event.fireEvent('beforebuild', obj);
18305             
18306             var opar = obj.parent;
18307             try { 
18308                 obj.parent = this.toObject(opar);
18309             } catch(e) {
18310                 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
18311                 return;
18312             }
18313             
18314             if (!obj.parent) {
18315                 Roo.debug && Roo.log("GOT top level module");
18316                 Roo.debug && Roo.log(obj);
18317                 obj.modules = new Roo.util.MixedCollection(false, 
18318                     function(o) { return o.order + '' }
18319                 );
18320                 this.topModule = obj;
18321                 return;
18322             }
18323                         // parent is a string (usually a dom element name..)
18324             if (typeof(obj.parent) == 'string') {
18325                 this.elmodules.push(obj);
18326                 return;
18327             }
18328             if (obj.parent.constructor != Roo.XComponent) {
18329                 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
18330             }
18331             if (!obj.parent.modules) {
18332                 obj.parent.modules = new Roo.util.MixedCollection(false, 
18333                     function(o) { return o.order + '' }
18334                 );
18335             }
18336             if (obj.parent.disabled) {
18337                 obj.disabled = true;
18338             }
18339             obj.parent.modules.add(obj);
18340         }, this);
18341     },
18342     
18343      /**
18344      * make a list of modules to build.
18345      * @return {Array} list of modules. 
18346      */ 
18347     
18348     buildOrder : function()
18349     {
18350         var _this = this;
18351         var cmp = function(a,b) {   
18352             return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
18353         };
18354         if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
18355             throw "No top level modules to build";
18356         }
18357         
18358         // make a flat list in order of modules to build.
18359         var mods = this.topModule ? [ this.topModule ] : [];
18360                 
18361         
18362         // elmodules (is a list of DOM based modules )
18363         Roo.each(this.elmodules, function(e) {
18364             mods.push(e);
18365             if (!this.topModule &&
18366                 typeof(e.parent) == 'string' &&
18367                 e.parent.substring(0,1) == '#' &&
18368                 Roo.get(e.parent.substr(1))
18369                ) {
18370                 
18371                 _this.topModule = e;
18372             }
18373             
18374         });
18375
18376         
18377         // add modules to their parents..
18378         var addMod = function(m) {
18379             Roo.debug && Roo.log("build Order: add: " + m.name);
18380                 
18381             mods.push(m);
18382             if (m.modules && !m.disabled) {
18383                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
18384                 m.modules.keySort('ASC',  cmp );
18385                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
18386     
18387                 m.modules.each(addMod);
18388             } else {
18389                 Roo.debug && Roo.log("build Order: no child modules");
18390             }
18391             // not sure if this is used any more..
18392             if (m.finalize) {
18393                 m.finalize.name = m.name + " (clean up) ";
18394                 mods.push(m.finalize);
18395             }
18396             
18397         }
18398         if (this.topModule && this.topModule.modules) { 
18399             this.topModule.modules.keySort('ASC',  cmp );
18400             this.topModule.modules.each(addMod);
18401         } 
18402         return mods;
18403     },
18404     
18405      /**
18406      * Build the registered modules.
18407      * @param {Object} parent element.
18408      * @param {Function} optional method to call after module has been added.
18409      * 
18410      */ 
18411    
18412     build : function(opts) 
18413     {
18414         
18415         if (typeof(opts) != 'undefined') {
18416             Roo.apply(this,opts);
18417         }
18418         
18419         this.preBuild();
18420         var mods = this.buildOrder();
18421       
18422         //this.allmods = mods;
18423         //Roo.debug && Roo.log(mods);
18424         //return;
18425         if (!mods.length) { // should not happen
18426             throw "NO modules!!!";
18427         }
18428         
18429         
18430         var msg = "Building Interface...";
18431         // flash it up as modal - so we store the mask!?
18432         if (!this.hideProgress && Roo.MessageBox) {
18433             Roo.MessageBox.show({ title: 'loading' });
18434             Roo.MessageBox.show({
18435                title: "Please wait...",
18436                msg: msg,
18437                width:450,
18438                progress:true,
18439                buttons : false,
18440                closable:false,
18441                modal: false
18442               
18443             });
18444         }
18445         var total = mods.length;
18446         
18447         var _this = this;
18448         var progressRun = function() {
18449             if (!mods.length) {
18450                 Roo.debug && Roo.log('hide?');
18451                 if (!this.hideProgress && Roo.MessageBox) {
18452                     Roo.MessageBox.hide();
18453                 }
18454                 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
18455                 
18456                 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
18457                 
18458                 // THE END...
18459                 return false;   
18460             }
18461             
18462             var m = mods.shift();
18463             
18464             
18465             Roo.debug && Roo.log(m);
18466             // not sure if this is supported any more.. - modules that are are just function
18467             if (typeof(m) == 'function') { 
18468                 m.call(this);
18469                 return progressRun.defer(10, _this);
18470             } 
18471             
18472             
18473             msg = "Building Interface " + (total  - mods.length) + 
18474                     " of " + total + 
18475                     (m.name ? (' - ' + m.name) : '');
18476                         Roo.debug && Roo.log(msg);
18477             if (!_this.hideProgress &&  Roo.MessageBox) { 
18478                 Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
18479             }
18480             
18481          
18482             // is the module disabled?
18483             var disabled = (typeof(m.disabled) == 'function') ?
18484                 m.disabled.call(m.module.disabled) : m.disabled;    
18485             
18486             
18487             if (disabled) {
18488                 return progressRun(); // we do not update the display!
18489             }
18490             
18491             // now build 
18492             
18493                         
18494                         
18495             m.render();
18496             // it's 10 on top level, and 1 on others??? why...
18497             return progressRun.defer(10, _this);
18498              
18499         }
18500         progressRun.defer(1, _this);
18501      
18502         
18503         
18504     },
18505     /**
18506      * Overlay a set of modified strings onto a component
18507      * This is dependant on our builder exporting the strings and 'named strings' elements.
18508      * 
18509      * @param {Object} element to overlay on - eg. Pman.Dialog.Login
18510      * @param {Object} associative array of 'named' string and it's new value.
18511      * 
18512      */
18513         overlayStrings : function( component, strings )
18514     {
18515         if (typeof(component['_named_strings']) == 'undefined') {
18516             throw "ERROR: component does not have _named_strings";
18517         }
18518         for ( var k in strings ) {
18519             var md = typeof(component['_named_strings'][k]) == 'undefined' ? false : component['_named_strings'][k];
18520             if (md !== false) {
18521                 component['_strings'][md] = strings[k];
18522             } else {
18523                 Roo.log('could not find named string: ' + k + ' in');
18524                 Roo.log(component);
18525             }
18526             
18527         }
18528         
18529     },
18530     
18531         
18532         /**
18533          * Event Object.
18534          *
18535          *
18536          */
18537         event: false, 
18538     /**
18539          * wrapper for event.on - aliased later..  
18540          * Typically use to register a event handler for register:
18541          *
18542          * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
18543          *
18544          */
18545     on : false
18546    
18547     
18548     
18549 });
18550
18551 Roo.XComponent.event = new Roo.util.Observable({
18552                 events : { 
18553                         /**
18554                          * @event register
18555                          * Fires when an Component is registered,
18556                          * set the disable property on the Component to stop registration.
18557                          * @param {Roo.XComponent} c the component being registerd.
18558                          * 
18559                          */
18560                         'register' : true,
18561             /**
18562                          * @event beforebuild
18563                          * Fires before each Component is built
18564                          * can be used to apply permissions.
18565                          * @param {Roo.XComponent} c the component being registerd.
18566                          * 
18567                          */
18568                         'beforebuild' : true,
18569                         /**
18570                          * @event buildcomplete
18571                          * Fires on the top level element when all elements have been built
18572                          * @param {Roo.XComponent} the top level component.
18573                          */
18574                         'buildcomplete' : true
18575                         
18576                 }
18577 });
18578
18579 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event); 
18580  //
18581  /**
18582  * marked - a markdown parser
18583  * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
18584  * https://github.com/chjj/marked
18585  */
18586
18587
18588 /**
18589  *
18590  * Roo.Markdown - is a very crude wrapper around marked..
18591  *
18592  * usage:
18593  * 
18594  * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
18595  * 
18596  * Note: move the sample code to the bottom of this
18597  * file before uncommenting it.
18598  *
18599  */
18600
18601 Roo.Markdown = {};
18602 Roo.Markdown.toHtml = function(text) {
18603     
18604     var c = new Roo.Markdown.marked.setOptions({
18605             renderer: new Roo.Markdown.marked.Renderer(),
18606             gfm: true,
18607             tables: true,
18608             breaks: false,
18609             pedantic: false,
18610             sanitize: false,
18611             smartLists: true,
18612             smartypants: false
18613           });
18614     // A FEW HACKS!!?
18615     
18616     text = text.replace(/\\\n/g,' ');
18617     return Roo.Markdown.marked(text);
18618 };
18619 //
18620 // converter
18621 //
18622 // Wraps all "globals" so that the only thing
18623 // exposed is makeHtml().
18624 //
18625 (function() {
18626     
18627      /**
18628          * eval:var:escape
18629          * eval:var:unescape
18630          * eval:var:replace
18631          */
18632       
18633     /**
18634      * Helpers
18635      */
18636     
18637     var escape = function (html, encode) {
18638       return html
18639         .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&amp;')
18640         .replace(/</g, '&lt;')
18641         .replace(/>/g, '&gt;')
18642         .replace(/"/g, '&quot;')
18643         .replace(/'/g, '&#39;');
18644     }
18645     
18646     var unescape = function (html) {
18647         // explicitly match decimal, hex, and named HTML entities 
18648       return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
18649         n = n.toLowerCase();
18650         if (n === 'colon') { return ':'; }
18651         if (n.charAt(0) === '#') {
18652           return n.charAt(1) === 'x'
18653             ? String.fromCharCode(parseInt(n.substring(2), 16))
18654             : String.fromCharCode(+n.substring(1));
18655         }
18656         return '';
18657       });
18658     }
18659     
18660     var replace = function (regex, opt) {
18661       regex = regex.source;
18662       opt = opt || '';
18663       return function self(name, val) {
18664         if (!name) { return new RegExp(regex, opt); }
18665         val = val.source || val;
18666         val = val.replace(/(^|[^\[])\^/g, '$1');
18667         regex = regex.replace(name, val);
18668         return self;
18669       };
18670     }
18671
18672
18673          /**
18674          * eval:var:noop
18675     */
18676     var noop = function () {}
18677     noop.exec = noop;
18678     
18679          /**
18680          * eval:var:merge
18681     */
18682     var merge = function (obj) {
18683       var i = 1
18684         , target
18685         , key;
18686     
18687       for (; i < arguments.length; i++) {
18688         target = arguments[i];
18689         for (key in target) {
18690           if (Object.prototype.hasOwnProperty.call(target, key)) {
18691             obj[key] = target[key];
18692           }
18693         }
18694       }
18695     
18696       return obj;
18697     }
18698     
18699     
18700     /**
18701      * Block-Level Grammar
18702      */
18703     
18704     
18705     
18706     
18707     var block = {
18708       newline: /^\n+/,
18709       code: /^( {4}[^\n]+\n*)+/,
18710       fences: noop,
18711       hr: /^( *[-*_]){3,} *(?:\n+|$)/,
18712       heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
18713       nptable: noop,
18714       lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
18715       blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
18716       list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
18717       html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
18718       def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
18719       table: noop,
18720       paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
18721       text: /^[^\n]+/
18722     };
18723     
18724     block.bullet = /(?:[*+-]|\d+\.)/;
18725     block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
18726     block.item = replace(block.item, 'gm')
18727       (/bull/g, block.bullet)
18728       ();
18729     
18730     block.list = replace(block.list)
18731       (/bull/g, block.bullet)
18732       ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
18733       ('def', '\\n+(?=' + block.def.source + ')')
18734       ();
18735     
18736     block.blockquote = replace(block.blockquote)
18737       ('def', block.def)
18738       ();
18739     
18740     block._tag = '(?!(?:'
18741       + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
18742       + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
18743       + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
18744     
18745     block.html = replace(block.html)
18746       ('comment', /<!--[\s\S]*?-->/)
18747       ('closed', /<(tag)[\s\S]+?<\/\1>/)
18748       ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
18749       (/tag/g, block._tag)
18750       ();
18751     
18752     block.paragraph = replace(block.paragraph)
18753       ('hr', block.hr)
18754       ('heading', block.heading)
18755       ('lheading', block.lheading)
18756       ('blockquote', block.blockquote)
18757       ('tag', '<' + block._tag)
18758       ('def', block.def)
18759       ();
18760     
18761     /**
18762      * Normal Block Grammar
18763      */
18764     
18765     block.normal = merge({}, block);
18766     
18767     /**
18768      * GFM Block Grammar
18769      */
18770     
18771     block.gfm = merge({}, block.normal, {
18772       fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
18773       paragraph: /^/,
18774       heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
18775     });
18776     
18777     block.gfm.paragraph = replace(block.paragraph)
18778       ('(?!', '(?!'
18779         + block.gfm.fences.source.replace('\\1', '\\2') + '|'
18780         + block.list.source.replace('\\1', '\\3') + '|')
18781       ();
18782     
18783     /**
18784      * GFM + Tables Block Grammar
18785      */
18786     
18787     block.tables = merge({}, block.gfm, {
18788       nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
18789       table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
18790     });
18791     
18792     /**
18793      * Block Lexer
18794      */
18795     
18796     var Lexer = function (options) {
18797       this.tokens = [];
18798       this.tokens.links = {};
18799       this.options = options || marked.defaults;
18800       this.rules = block.normal;
18801     
18802       if (this.options.gfm) {
18803         if (this.options.tables) {
18804           this.rules = block.tables;
18805         } else {
18806           this.rules = block.gfm;
18807         }
18808       }
18809     }
18810     
18811     /**
18812      * Expose Block Rules
18813      */
18814     
18815     Lexer.rules = block;
18816     
18817     /**
18818      * Static Lex Method
18819      */
18820     
18821     Lexer.lex = function(src, options) {
18822       var lexer = new Lexer(options);
18823       return lexer.lex(src);
18824     };
18825     
18826     /**
18827      * Preprocessing
18828      */
18829     
18830     Lexer.prototype.lex = function(src) {
18831       src = src
18832         .replace(/\r\n|\r/g, '\n')
18833         .replace(/\t/g, '    ')
18834         .replace(/\u00a0/g, ' ')
18835         .replace(/\u2424/g, '\n');
18836     
18837       return this.token(src, true);
18838     };
18839     
18840     /**
18841      * Lexing
18842      */
18843     
18844     Lexer.prototype.token = function(src, top, bq) {
18845       var src = src.replace(/^ +$/gm, '')
18846         , next
18847         , loose
18848         , cap
18849         , bull
18850         , b
18851         , item
18852         , space
18853         , i
18854         , l;
18855     
18856       while (src) {
18857         // newline
18858         if (cap = this.rules.newline.exec(src)) {
18859           src = src.substring(cap[0].length);
18860           if (cap[0].length > 1) {
18861             this.tokens.push({
18862               type: 'space'
18863             });
18864           }
18865         }
18866     
18867         // code
18868         if (cap = this.rules.code.exec(src)) {
18869           src = src.substring(cap[0].length);
18870           cap = cap[0].replace(/^ {4}/gm, '');
18871           this.tokens.push({
18872             type: 'code',
18873             text: !this.options.pedantic
18874               ? cap.replace(/\n+$/, '')
18875               : cap
18876           });
18877           continue;
18878         }
18879     
18880         // fences (gfm)
18881         if (cap = this.rules.fences.exec(src)) {
18882           src = src.substring(cap[0].length);
18883           this.tokens.push({
18884             type: 'code',
18885             lang: cap[2],
18886             text: cap[3] || ''
18887           });
18888           continue;
18889         }
18890     
18891         // heading
18892         if (cap = this.rules.heading.exec(src)) {
18893           src = src.substring(cap[0].length);
18894           this.tokens.push({
18895             type: 'heading',
18896             depth: cap[1].length,
18897             text: cap[2]
18898           });
18899           continue;
18900         }
18901     
18902         // table no leading pipe (gfm)
18903         if (top && (cap = this.rules.nptable.exec(src))) {
18904           src = src.substring(cap[0].length);
18905     
18906           item = {
18907             type: 'table',
18908             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
18909             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
18910             cells: cap[3].replace(/\n$/, '').split('\n')
18911           };
18912     
18913           for (i = 0; i < item.align.length; i++) {
18914             if (/^ *-+: *$/.test(item.align[i])) {
18915               item.align[i] = 'right';
18916             } else if (/^ *:-+: *$/.test(item.align[i])) {
18917               item.align[i] = 'center';
18918             } else if (/^ *:-+ *$/.test(item.align[i])) {
18919               item.align[i] = 'left';
18920             } else {
18921               item.align[i] = null;
18922             }
18923           }
18924     
18925           for (i = 0; i < item.cells.length; i++) {
18926             item.cells[i] = item.cells[i].split(/ *\| */);
18927           }
18928     
18929           this.tokens.push(item);
18930     
18931           continue;
18932         }
18933     
18934         // lheading
18935         if (cap = this.rules.lheading.exec(src)) {
18936           src = src.substring(cap[0].length);
18937           this.tokens.push({
18938             type: 'heading',
18939             depth: cap[2] === '=' ? 1 : 2,
18940             text: cap[1]
18941           });
18942           continue;
18943         }
18944     
18945         // hr
18946         if (cap = this.rules.hr.exec(src)) {
18947           src = src.substring(cap[0].length);
18948           this.tokens.push({
18949             type: 'hr'
18950           });
18951           continue;
18952         }
18953     
18954         // blockquote
18955         if (cap = this.rules.blockquote.exec(src)) {
18956           src = src.substring(cap[0].length);
18957     
18958           this.tokens.push({
18959             type: 'blockquote_start'
18960           });
18961     
18962           cap = cap[0].replace(/^ *> ?/gm, '');
18963     
18964           // Pass `top` to keep the current
18965           // "toplevel" state. This is exactly
18966           // how markdown.pl works.
18967           this.token(cap, top, true);
18968     
18969           this.tokens.push({
18970             type: 'blockquote_end'
18971           });
18972     
18973           continue;
18974         }
18975     
18976         // list
18977         if (cap = this.rules.list.exec(src)) {
18978           src = src.substring(cap[0].length);
18979           bull = cap[2];
18980     
18981           this.tokens.push({
18982             type: 'list_start',
18983             ordered: bull.length > 1
18984           });
18985     
18986           // Get each top-level item.
18987           cap = cap[0].match(this.rules.item);
18988     
18989           next = false;
18990           l = cap.length;
18991           i = 0;
18992     
18993           for (; i < l; i++) {
18994             item = cap[i];
18995     
18996             // Remove the list item's bullet
18997             // so it is seen as the next token.
18998             space = item.length;
18999             item = item.replace(/^ *([*+-]|\d+\.) +/, '');
19000     
19001             // Outdent whatever the
19002             // list item contains. Hacky.
19003             if (~item.indexOf('\n ')) {
19004               space -= item.length;
19005               item = !this.options.pedantic
19006                 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
19007                 : item.replace(/^ {1,4}/gm, '');
19008             }
19009     
19010             // Determine whether the next list item belongs here.
19011             // Backpedal if it does not belong in this list.
19012             if (this.options.smartLists && i !== l - 1) {
19013               b = block.bullet.exec(cap[i + 1])[0];
19014               if (bull !== b && !(bull.length > 1 && b.length > 1)) {
19015                 src = cap.slice(i + 1).join('\n') + src;
19016                 i = l - 1;
19017               }
19018             }
19019     
19020             // Determine whether item is loose or not.
19021             // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
19022             // for discount behavior.
19023             loose = next || /\n\n(?!\s*$)/.test(item);
19024             if (i !== l - 1) {
19025               next = item.charAt(item.length - 1) === '\n';
19026               if (!loose) { loose = next; }
19027             }
19028     
19029             this.tokens.push({
19030               type: loose
19031                 ? 'loose_item_start'
19032                 : 'list_item_start'
19033             });
19034     
19035             // Recurse.
19036             this.token(item, false, bq);
19037     
19038             this.tokens.push({
19039               type: 'list_item_end'
19040             });
19041           }
19042     
19043           this.tokens.push({
19044             type: 'list_end'
19045           });
19046     
19047           continue;
19048         }
19049     
19050         // html
19051         if (cap = this.rules.html.exec(src)) {
19052           src = src.substring(cap[0].length);
19053           this.tokens.push({
19054             type: this.options.sanitize
19055               ? 'paragraph'
19056               : 'html',
19057             pre: !this.options.sanitizer
19058               && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
19059             text: cap[0]
19060           });
19061           continue;
19062         }
19063     
19064         // def
19065         if ((!bq && top) && (cap = this.rules.def.exec(src))) {
19066           src = src.substring(cap[0].length);
19067           this.tokens.links[cap[1].toLowerCase()] = {
19068             href: cap[2],
19069             title: cap[3]
19070           };
19071           continue;
19072         }
19073     
19074         // table (gfm)
19075         if (top && (cap = this.rules.table.exec(src))) {
19076           src = src.substring(cap[0].length);
19077     
19078           item = {
19079             type: 'table',
19080             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
19081             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
19082             cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
19083           };
19084     
19085           for (i = 0; i < item.align.length; i++) {
19086             if (/^ *-+: *$/.test(item.align[i])) {
19087               item.align[i] = 'right';
19088             } else if (/^ *:-+: *$/.test(item.align[i])) {
19089               item.align[i] = 'center';
19090             } else if (/^ *:-+ *$/.test(item.align[i])) {
19091               item.align[i] = 'left';
19092             } else {
19093               item.align[i] = null;
19094             }
19095           }
19096     
19097           for (i = 0; i < item.cells.length; i++) {
19098             item.cells[i] = item.cells[i]
19099               .replace(/^ *\| *| *\| *$/g, '')
19100               .split(/ *\| */);
19101           }
19102     
19103           this.tokens.push(item);
19104     
19105           continue;
19106         }
19107     
19108         // top-level paragraph
19109         if (top && (cap = this.rules.paragraph.exec(src))) {
19110           src = src.substring(cap[0].length);
19111           this.tokens.push({
19112             type: 'paragraph',
19113             text: cap[1].charAt(cap[1].length - 1) === '\n'
19114               ? cap[1].slice(0, -1)
19115               : cap[1]
19116           });
19117           continue;
19118         }
19119     
19120         // text
19121         if (cap = this.rules.text.exec(src)) {
19122           // Top-level should never reach here.
19123           src = src.substring(cap[0].length);
19124           this.tokens.push({
19125             type: 'text',
19126             text: cap[0]
19127           });
19128           continue;
19129         }
19130     
19131         if (src) {
19132           throw new
19133             Error('Infinite loop on byte: ' + src.charCodeAt(0));
19134         }
19135       }
19136     
19137       return this.tokens;
19138     };
19139     
19140     /**
19141      * Inline-Level Grammar
19142      */
19143     
19144     var inline = {
19145       escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
19146       autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
19147       url: noop,
19148       tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
19149       link: /^!?\[(inside)\]\(href\)/,
19150       reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
19151       nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
19152       strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
19153       em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
19154       code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
19155       br: /^ {2,}\n(?!\s*$)/,
19156       del: noop,
19157       text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
19158     };
19159     
19160     inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
19161     inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
19162     
19163     inline.link = replace(inline.link)
19164       ('inside', inline._inside)
19165       ('href', inline._href)
19166       ();
19167     
19168     inline.reflink = replace(inline.reflink)
19169       ('inside', inline._inside)
19170       ();
19171     
19172     /**
19173      * Normal Inline Grammar
19174      */
19175     
19176     inline.normal = merge({}, inline);
19177     
19178     /**
19179      * Pedantic Inline Grammar
19180      */
19181     
19182     inline.pedantic = merge({}, inline.normal, {
19183       strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
19184       em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
19185     });
19186     
19187     /**
19188      * GFM Inline Grammar
19189      */
19190     
19191     inline.gfm = merge({}, inline.normal, {
19192       escape: replace(inline.escape)('])', '~|])')(),
19193       url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
19194       del: /^~~(?=\S)([\s\S]*?\S)~~/,
19195       text: replace(inline.text)
19196         (']|', '~]|')
19197         ('|', '|https?://|')
19198         ()
19199     });
19200     
19201     /**
19202      * GFM + Line Breaks Inline Grammar
19203      */
19204     
19205     inline.breaks = merge({}, inline.gfm, {
19206       br: replace(inline.br)('{2,}', '*')(),
19207       text: replace(inline.gfm.text)('{2,}', '*')()
19208     });
19209     
19210     /**
19211      * Inline Lexer & Compiler
19212      */
19213     
19214     var InlineLexer  = function (links, options) {
19215       this.options = options || marked.defaults;
19216       this.links = links;
19217       this.rules = inline.normal;
19218       this.renderer = this.options.renderer || new Renderer;
19219       this.renderer.options = this.options;
19220     
19221       if (!this.links) {
19222         throw new
19223           Error('Tokens array requires a `links` property.');
19224       }
19225     
19226       if (this.options.gfm) {
19227         if (this.options.breaks) {
19228           this.rules = inline.breaks;
19229         } else {
19230           this.rules = inline.gfm;
19231         }
19232       } else if (this.options.pedantic) {
19233         this.rules = inline.pedantic;
19234       }
19235     }
19236     
19237     /**
19238      * Expose Inline Rules
19239      */
19240     
19241     InlineLexer.rules = inline;
19242     
19243     /**
19244      * Static Lexing/Compiling Method
19245      */
19246     
19247     InlineLexer.output = function(src, links, options) {
19248       var inline = new InlineLexer(links, options);
19249       return inline.output(src);
19250     };
19251     
19252     /**
19253      * Lexing/Compiling
19254      */
19255     
19256     InlineLexer.prototype.output = function(src) {
19257       var out = ''
19258         , link
19259         , text
19260         , href
19261         , cap;
19262     
19263       while (src) {
19264         // escape
19265         if (cap = this.rules.escape.exec(src)) {
19266           src = src.substring(cap[0].length);
19267           out += cap[1];
19268           continue;
19269         }
19270     
19271         // autolink
19272         if (cap = this.rules.autolink.exec(src)) {
19273           src = src.substring(cap[0].length);
19274           if (cap[2] === '@') {
19275             text = cap[1].charAt(6) === ':'
19276               ? this.mangle(cap[1].substring(7))
19277               : this.mangle(cap[1]);
19278             href = this.mangle('mailto:') + text;
19279           } else {
19280             text = escape(cap[1]);
19281             href = text;
19282           }
19283           out += this.renderer.link(href, null, text);
19284           continue;
19285         }
19286     
19287         // url (gfm)
19288         if (!this.inLink && (cap = this.rules.url.exec(src))) {
19289           src = src.substring(cap[0].length);
19290           text = escape(cap[1]);
19291           href = text;
19292           out += this.renderer.link(href, null, text);
19293           continue;
19294         }
19295     
19296         // tag
19297         if (cap = this.rules.tag.exec(src)) {
19298           if (!this.inLink && /^<a /i.test(cap[0])) {
19299             this.inLink = true;
19300           } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
19301             this.inLink = false;
19302           }
19303           src = src.substring(cap[0].length);
19304           out += this.options.sanitize
19305             ? this.options.sanitizer
19306               ? this.options.sanitizer(cap[0])
19307               : escape(cap[0])
19308             : cap[0];
19309           continue;
19310         }
19311     
19312         // link
19313         if (cap = this.rules.link.exec(src)) {
19314           src = src.substring(cap[0].length);
19315           this.inLink = true;
19316           out += this.outputLink(cap, {
19317             href: cap[2],
19318             title: cap[3]
19319           });
19320           this.inLink = false;
19321           continue;
19322         }
19323     
19324         // reflink, nolink
19325         if ((cap = this.rules.reflink.exec(src))
19326             || (cap = this.rules.nolink.exec(src))) {
19327           src = src.substring(cap[0].length);
19328           link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
19329           link = this.links[link.toLowerCase()];
19330           if (!link || !link.href) {
19331             out += cap[0].charAt(0);
19332             src = cap[0].substring(1) + src;
19333             continue;
19334           }
19335           this.inLink = true;
19336           out += this.outputLink(cap, link);
19337           this.inLink = false;
19338           continue;
19339         }
19340     
19341         // strong
19342         if (cap = this.rules.strong.exec(src)) {
19343           src = src.substring(cap[0].length);
19344           out += this.renderer.strong(this.output(cap[2] || cap[1]));
19345           continue;
19346         }
19347     
19348         // em
19349         if (cap = this.rules.em.exec(src)) {
19350           src = src.substring(cap[0].length);
19351           out += this.renderer.em(this.output(cap[2] || cap[1]));
19352           continue;
19353         }
19354     
19355         // code
19356         if (cap = this.rules.code.exec(src)) {
19357           src = src.substring(cap[0].length);
19358           out += this.renderer.codespan(escape(cap[2], true));
19359           continue;
19360         }
19361     
19362         // br
19363         if (cap = this.rules.br.exec(src)) {
19364           src = src.substring(cap[0].length);
19365           out += this.renderer.br();
19366           continue;
19367         }
19368     
19369         // del (gfm)
19370         if (cap = this.rules.del.exec(src)) {
19371           src = src.substring(cap[0].length);
19372           out += this.renderer.del(this.output(cap[1]));
19373           continue;
19374         }
19375     
19376         // text
19377         if (cap = this.rules.text.exec(src)) {
19378           src = src.substring(cap[0].length);
19379           out += this.renderer.text(escape(this.smartypants(cap[0])));
19380           continue;
19381         }
19382     
19383         if (src) {
19384           throw new
19385             Error('Infinite loop on byte: ' + src.charCodeAt(0));
19386         }
19387       }
19388     
19389       return out;
19390     };
19391     
19392     /**
19393      * Compile Link
19394      */
19395     
19396     InlineLexer.prototype.outputLink = function(cap, link) {
19397       var href = escape(link.href)
19398         , title = link.title ? escape(link.title) : null;
19399     
19400       return cap[0].charAt(0) !== '!'
19401         ? this.renderer.link(href, title, this.output(cap[1]))
19402         : this.renderer.image(href, title, escape(cap[1]));
19403     };
19404     
19405     /**
19406      * Smartypants Transformations
19407      */
19408     
19409     InlineLexer.prototype.smartypants = function(text) {
19410       if (!this.options.smartypants)  { return text; }
19411       return text
19412         // em-dashes
19413         .replace(/---/g, '\u2014')
19414         // en-dashes
19415         .replace(/--/g, '\u2013')
19416         // opening singles
19417         .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
19418         // closing singles & apostrophes
19419         .replace(/'/g, '\u2019')
19420         // opening doubles
19421         .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
19422         // closing doubles
19423         .replace(/"/g, '\u201d')
19424         // ellipses
19425         .replace(/\.{3}/g, '\u2026');
19426     };
19427     
19428     /**
19429      * Mangle Links
19430      */
19431     
19432     InlineLexer.prototype.mangle = function(text) {
19433       if (!this.options.mangle) { return text; }
19434       var out = ''
19435         , l = text.length
19436         , i = 0
19437         , ch;
19438     
19439       for (; i < l; i++) {
19440         ch = text.charCodeAt(i);
19441         if (Math.random() > 0.5) {
19442           ch = 'x' + ch.toString(16);
19443         }
19444         out += '&#' + ch + ';';
19445       }
19446     
19447       return out;
19448     };
19449     
19450     /**
19451      * Renderer
19452      */
19453     
19454      /**
19455          * eval:var:Renderer
19456     */
19457     
19458     var Renderer   = function (options) {
19459       this.options = options || {};
19460     }
19461     
19462     Renderer.prototype.code = function(code, lang, escaped) {
19463       if (this.options.highlight) {
19464         var out = this.options.highlight(code, lang);
19465         if (out != null && out !== code) {
19466           escaped = true;
19467           code = out;
19468         }
19469       } else {
19470             // hack!!! - it's already escapeD?
19471             escaped = true;
19472       }
19473     
19474       if (!lang) {
19475         return '<pre><code>'
19476           + (escaped ? code : escape(code, true))
19477           + '\n</code></pre>';
19478       }
19479     
19480       return '<pre><code class="'
19481         + this.options.langPrefix
19482         + escape(lang, true)
19483         + '">'
19484         + (escaped ? code : escape(code, true))
19485         + '\n</code></pre>\n';
19486     };
19487     
19488     Renderer.prototype.blockquote = function(quote) {
19489       return '<blockquote>\n' + quote + '</blockquote>\n';
19490     };
19491     
19492     Renderer.prototype.html = function(html) {
19493       return html;
19494     };
19495     
19496     Renderer.prototype.heading = function(text, level, raw) {
19497       return '<h'
19498         + level
19499         + ' id="'
19500         + this.options.headerPrefix
19501         + raw.toLowerCase().replace(/[^\w]+/g, '-')
19502         + '">'
19503         + text
19504         + '</h'
19505         + level
19506         + '>\n';
19507     };
19508     
19509     Renderer.prototype.hr = function() {
19510       return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
19511     };
19512     
19513     Renderer.prototype.list = function(body, ordered) {
19514       var type = ordered ? 'ol' : 'ul';
19515       return '<' + type + '>\n' + body + '</' + type + '>\n';
19516     };
19517     
19518     Renderer.prototype.listitem = function(text) {
19519       return '<li>' + text + '</li>\n';
19520     };
19521     
19522     Renderer.prototype.paragraph = function(text) {
19523       return '<p>' + text + '</p>\n';
19524     };
19525     
19526     Renderer.prototype.table = function(header, body) {
19527       return '<table class="table table-striped">\n'
19528         + '<thead>\n'
19529         + header
19530         + '</thead>\n'
19531         + '<tbody>\n'
19532         + body
19533         + '</tbody>\n'
19534         + '</table>\n';
19535     };
19536     
19537     Renderer.prototype.tablerow = function(content) {
19538       return '<tr>\n' + content + '</tr>\n';
19539     };
19540     
19541     Renderer.prototype.tablecell = function(content, flags) {
19542       var type = flags.header ? 'th' : 'td';
19543       var tag = flags.align
19544         ? '<' + type + ' style="text-align:' + flags.align + '">'
19545         : '<' + type + '>';
19546       return tag + content + '</' + type + '>\n';
19547     };
19548     
19549     // span level renderer
19550     Renderer.prototype.strong = function(text) {
19551       return '<strong>' + text + '</strong>';
19552     };
19553     
19554     Renderer.prototype.em = function(text) {
19555       return '<em>' + text + '</em>';
19556     };
19557     
19558     Renderer.prototype.codespan = function(text) {
19559       return '<code>' + text + '</code>';
19560     };
19561     
19562     Renderer.prototype.br = function() {
19563       return this.options.xhtml ? '<br/>' : '<br>';
19564     };
19565     
19566     Renderer.prototype.del = function(text) {
19567       return '<del>' + text + '</del>';
19568     };
19569     
19570     Renderer.prototype.link = function(href, title, text) {
19571       if (this.options.sanitize) {
19572         try {
19573           var prot = decodeURIComponent(unescape(href))
19574             .replace(/[^\w:]/g, '')
19575             .toLowerCase();
19576         } catch (e) {
19577           return '';
19578         }
19579         if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
19580           return '';
19581         }
19582       }
19583       var out = '<a href="' + href + '"';
19584       if (title) {
19585         out += ' title="' + title + '"';
19586       }
19587       out += '>' + text + '</a>';
19588       return out;
19589     };
19590     
19591     Renderer.prototype.image = function(href, title, text) {
19592       var out = '<img src="' + href + '" alt="' + text + '"';
19593       if (title) {
19594         out += ' title="' + title + '"';
19595       }
19596       out += this.options.xhtml ? '/>' : '>';
19597       return out;
19598     };
19599     
19600     Renderer.prototype.text = function(text) {
19601       return text;
19602     };
19603     
19604     /**
19605      * Parsing & Compiling
19606      */
19607          /**
19608          * eval:var:Parser
19609     */
19610     
19611     var Parser= function (options) {
19612       this.tokens = [];
19613       this.token = null;
19614       this.options = options || marked.defaults;
19615       this.options.renderer = this.options.renderer || new Renderer;
19616       this.renderer = this.options.renderer;
19617       this.renderer.options = this.options;
19618     }
19619     
19620     /**
19621      * Static Parse Method
19622      */
19623     
19624     Parser.parse = function(src, options, renderer) {
19625       var parser = new Parser(options, renderer);
19626       return parser.parse(src);
19627     };
19628     
19629     /**
19630      * Parse Loop
19631      */
19632     
19633     Parser.prototype.parse = function(src) {
19634       this.inline = new InlineLexer(src.links, this.options, this.renderer);
19635       this.tokens = src.reverse();
19636     
19637       var out = '';
19638       while (this.next()) {
19639         out += this.tok();
19640       }
19641     
19642       return out;
19643     };
19644     
19645     /**
19646      * Next Token
19647      */
19648     
19649     Parser.prototype.next = function() {
19650       return this.token = this.tokens.pop();
19651     };
19652     
19653     /**
19654      * Preview Next Token
19655      */
19656     
19657     Parser.prototype.peek = function() {
19658       return this.tokens[this.tokens.length - 1] || 0;
19659     };
19660     
19661     /**
19662      * Parse Text Tokens
19663      */
19664     
19665     Parser.prototype.parseText = function() {
19666       var body = this.token.text;
19667     
19668       while (this.peek().type === 'text') {
19669         body += '\n' + this.next().text;
19670       }
19671     
19672       return this.inline.output(body);
19673     };
19674     
19675     /**
19676      * Parse Current Token
19677      */
19678     
19679     Parser.prototype.tok = function() {
19680       switch (this.token.type) {
19681         case 'space': {
19682           return '';
19683         }
19684         case 'hr': {
19685           return this.renderer.hr();
19686         }
19687         case 'heading': {
19688           return this.renderer.heading(
19689             this.inline.output(this.token.text),
19690             this.token.depth,
19691             this.token.text);
19692         }
19693         case 'code': {
19694           return this.renderer.code(this.token.text,
19695             this.token.lang,
19696             this.token.escaped);
19697         }
19698         case 'table': {
19699           var header = ''
19700             , body = ''
19701             , i
19702             , row
19703             , cell
19704             , flags
19705             , j;
19706     
19707           // header
19708           cell = '';
19709           for (i = 0; i < this.token.header.length; i++) {
19710             flags = { header: true, align: this.token.align[i] };
19711             cell += this.renderer.tablecell(
19712               this.inline.output(this.token.header[i]),
19713               { header: true, align: this.token.align[i] }
19714             );
19715           }
19716           header += this.renderer.tablerow(cell);
19717     
19718           for (i = 0; i < this.token.cells.length; i++) {
19719             row = this.token.cells[i];
19720     
19721             cell = '';
19722             for (j = 0; j < row.length; j++) {
19723               cell += this.renderer.tablecell(
19724                 this.inline.output(row[j]),
19725                 { header: false, align: this.token.align[j] }
19726               );
19727             }
19728     
19729             body += this.renderer.tablerow(cell);
19730           }
19731           return this.renderer.table(header, body);
19732         }
19733         case 'blockquote_start': {
19734           var body = '';
19735     
19736           while (this.next().type !== 'blockquote_end') {
19737             body += this.tok();
19738           }
19739     
19740           return this.renderer.blockquote(body);
19741         }
19742         case 'list_start': {
19743           var body = ''
19744             , ordered = this.token.ordered;
19745     
19746           while (this.next().type !== 'list_end') {
19747             body += this.tok();
19748           }
19749     
19750           return this.renderer.list(body, ordered);
19751         }
19752         case 'list_item_start': {
19753           var body = '';
19754     
19755           while (this.next().type !== 'list_item_end') {
19756             body += this.token.type === 'text'
19757               ? this.parseText()
19758               : this.tok();
19759           }
19760     
19761           return this.renderer.listitem(body);
19762         }
19763         case 'loose_item_start': {
19764           var body = '';
19765     
19766           while (this.next().type !== 'list_item_end') {
19767             body += this.tok();
19768           }
19769     
19770           return this.renderer.listitem(body);
19771         }
19772         case 'html': {
19773           var html = !this.token.pre && !this.options.pedantic
19774             ? this.inline.output(this.token.text)
19775             : this.token.text;
19776           return this.renderer.html(html);
19777         }
19778         case 'paragraph': {
19779           return this.renderer.paragraph(this.inline.output(this.token.text));
19780         }
19781         case 'text': {
19782           return this.renderer.paragraph(this.parseText());
19783         }
19784       }
19785     };
19786   
19787     
19788     /**
19789      * Marked
19790      */
19791          /**
19792          * eval:var:marked
19793     */
19794     var marked = function (src, opt, callback) {
19795       if (callback || typeof opt === 'function') {
19796         if (!callback) {
19797           callback = opt;
19798           opt = null;
19799         }
19800     
19801         opt = merge({}, marked.defaults, opt || {});
19802     
19803         var highlight = opt.highlight
19804           , tokens
19805           , pending
19806           , i = 0;
19807     
19808         try {
19809           tokens = Lexer.lex(src, opt)
19810         } catch (e) {
19811           return callback(e);
19812         }
19813     
19814         pending = tokens.length;
19815          /**
19816          * eval:var:done
19817     */
19818         var done = function(err) {
19819           if (err) {
19820             opt.highlight = highlight;
19821             return callback(err);
19822           }
19823     
19824           var out;
19825     
19826           try {
19827             out = Parser.parse(tokens, opt);
19828           } catch (e) {
19829             err = e;
19830           }
19831     
19832           opt.highlight = highlight;
19833     
19834           return err
19835             ? callback(err)
19836             : callback(null, out);
19837         };
19838     
19839         if (!highlight || highlight.length < 3) {
19840           return done();
19841         }
19842     
19843         delete opt.highlight;
19844     
19845         if (!pending) { return done(); }
19846     
19847         for (; i < tokens.length; i++) {
19848           (function(token) {
19849             if (token.type !== 'code') {
19850               return --pending || done();
19851             }
19852             return highlight(token.text, token.lang, function(err, code) {
19853               if (err) { return done(err); }
19854               if (code == null || code === token.text) {
19855                 return --pending || done();
19856               }
19857               token.text = code;
19858               token.escaped = true;
19859               --pending || done();
19860             });
19861           })(tokens[i]);
19862         }
19863     
19864         return;
19865       }
19866       try {
19867         if (opt) { opt = merge({}, marked.defaults, opt); }
19868         return Parser.parse(Lexer.lex(src, opt), opt);
19869       } catch (e) {
19870         e.message += '\nPlease report this to https://github.com/chjj/marked.';
19871         if ((opt || marked.defaults).silent) {
19872           return '<p>An error occured:</p><pre>'
19873             + escape(e.message + '', true)
19874             + '</pre>';
19875         }
19876         throw e;
19877       }
19878     }
19879     
19880     /**
19881      * Options
19882      */
19883     
19884     marked.options =
19885     marked.setOptions = function(opt) {
19886       merge(marked.defaults, opt);
19887       return marked;
19888     };
19889     
19890     marked.defaults = {
19891       gfm: true,
19892       tables: true,
19893       breaks: false,
19894       pedantic: false,
19895       sanitize: false,
19896       sanitizer: null,
19897       mangle: true,
19898       smartLists: false,
19899       silent: false,
19900       highlight: null,
19901       langPrefix: 'lang-',
19902       smartypants: false,
19903       headerPrefix: '',
19904       renderer: new Renderer,
19905       xhtml: false
19906     };
19907     
19908     /**
19909      * Expose
19910      */
19911     
19912     marked.Parser = Parser;
19913     marked.parser = Parser.parse;
19914     
19915     marked.Renderer = Renderer;
19916     
19917     marked.Lexer = Lexer;
19918     marked.lexer = Lexer.lex;
19919     
19920     marked.InlineLexer = InlineLexer;
19921     marked.inlineLexer = InlineLexer.output;
19922     
19923     marked.parse = marked;
19924     
19925     Roo.Markdown.marked = marked;
19926
19927 })();/*
19928  * Based on:
19929  * Ext JS Library 1.1.1
19930  * Copyright(c) 2006-2007, Ext JS, LLC.
19931  *
19932  * Originally Released Under LGPL - original licence link has changed is not relivant.
19933  *
19934  * Fork - LGPL
19935  * <script type="text/javascript">
19936  */
19937
19938
19939
19940 /*
19941  * These classes are derivatives of the similarly named classes in the YUI Library.
19942  * The original license:
19943  * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
19944  * Code licensed under the BSD License:
19945  * http://developer.yahoo.net/yui/license.txt
19946  */
19947
19948 (function() {
19949
19950 var Event=Roo.EventManager;
19951 var Dom=Roo.lib.Dom;
19952
19953 /**
19954  * @class Roo.dd.DragDrop
19955  * @extends Roo.util.Observable
19956  * Defines the interface and base operation of items that that can be
19957  * dragged or can be drop targets.  It was designed to be extended, overriding
19958  * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
19959  * Up to three html elements can be associated with a DragDrop instance:
19960  * <ul>
19961  * <li>linked element: the element that is passed into the constructor.
19962  * This is the element which defines the boundaries for interaction with
19963  * other DragDrop objects.</li>
19964  * <li>handle element(s): The drag operation only occurs if the element that
19965  * was clicked matches a handle element.  By default this is the linked
19966  * element, but there are times that you will want only a portion of the
19967  * linked element to initiate the drag operation, and the setHandleElId()
19968  * method provides a way to define this.</li>
19969  * <li>drag element: this represents the element that would be moved along
19970  * with the cursor during a drag operation.  By default, this is the linked
19971  * element itself as in {@link Roo.dd.DD}.  setDragElId() lets you define
19972  * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
19973  * </li>
19974  * </ul>
19975  * This class should not be instantiated until the onload event to ensure that
19976  * the associated elements are available.
19977  * The following would define a DragDrop obj that would interact with any
19978  * other DragDrop obj in the "group1" group:
19979  * <pre>
19980  *  dd = new Roo.dd.DragDrop("div1", "group1");
19981  * </pre>
19982  * Since none of the event handlers have been implemented, nothing would
19983  * actually happen if you were to run the code above.  Normally you would
19984  * override this class or one of the default implementations, but you can
19985  * also override the methods you want on an instance of the class...
19986  * <pre>
19987  *  dd.onDragDrop = function(e, id) {
19988  *  &nbsp;&nbsp;alert("dd was dropped on " + id);
19989  *  }
19990  * </pre>
19991  * @constructor
19992  * @param {String} id of the element that is linked to this instance
19993  * @param {String} sGroup the group of related DragDrop objects
19994  * @param {object} config an object containing configurable attributes
19995  *                Valid properties for DragDrop:
19996  *                    padding, isTarget, maintainOffset, primaryButtonOnly
19997  */
19998 Roo.dd.DragDrop = function(id, sGroup, config) {
19999     if (id) {
20000         this.init(id, sGroup, config);
20001     }
20002     
20003 };
20004
20005 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
20006
20007     /**
20008      * The id of the element associated with this object.  This is what we
20009      * refer to as the "linked element" because the size and position of
20010      * this element is used to determine when the drag and drop objects have
20011      * interacted.
20012      * @property id
20013      * @type String
20014      */
20015     id: null,
20016
20017     /**
20018      * Configuration attributes passed into the constructor
20019      * @property config
20020      * @type object
20021      */
20022     config: null,
20023
20024     /**
20025      * The id of the element that will be dragged.  By default this is same
20026      * as the linked element , but could be changed to another element. Ex:
20027      * Roo.dd.DDProxy
20028      * @property dragElId
20029      * @type String
20030      * @private
20031      */
20032     dragElId: null,
20033
20034     /**
20035      * the id of the element that initiates the drag operation.  By default
20036      * this is the linked element, but could be changed to be a child of this
20037      * element.  This lets us do things like only starting the drag when the
20038      * header element within the linked html element is clicked.
20039      * @property handleElId
20040      * @type String
20041      * @private
20042      */
20043     handleElId: null,
20044
20045     /**
20046      * An associative array of HTML tags that will be ignored if clicked.
20047      * @property invalidHandleTypes
20048      * @type {string: string}
20049      */
20050     invalidHandleTypes: null,
20051
20052     /**
20053      * An associative array of ids for elements that will be ignored if clicked
20054      * @property invalidHandleIds
20055      * @type {string: string}
20056      */
20057     invalidHandleIds: null,
20058
20059     /**
20060      * An indexted array of css class names for elements that will be ignored
20061      * if clicked.
20062      * @property invalidHandleClasses
20063      * @type string[]
20064      */
20065     invalidHandleClasses: null,
20066
20067     /**
20068      * The linked element's absolute X position at the time the drag was
20069      * started
20070      * @property startPageX
20071      * @type int
20072      * @private
20073      */
20074     startPageX: 0,
20075
20076     /**
20077      * The linked element's absolute X position at the time the drag was
20078      * started
20079      * @property startPageY
20080      * @type int
20081      * @private
20082      */
20083     startPageY: 0,
20084
20085     /**
20086      * The group defines a logical collection of DragDrop objects that are
20087      * related.  Instances only get events when interacting with other
20088      * DragDrop object in the same group.  This lets us define multiple
20089      * groups using a single DragDrop subclass if we want.
20090      * @property groups
20091      * @type {string: string}
20092      */
20093     groups: null,
20094
20095     /**
20096      * Individual drag/drop instances can be locked.  This will prevent
20097      * onmousedown start drag.
20098      * @property locked
20099      * @type boolean
20100      * @private
20101      */
20102     locked: false,
20103
20104     /**
20105      * Lock this instance
20106      * @method lock
20107      */
20108     lock: function() { this.locked = true; },
20109
20110     /**
20111      * Unlock this instace
20112      * @method unlock
20113      */
20114     unlock: function() { this.locked = false; },
20115
20116     /**
20117      * By default, all insances can be a drop target.  This can be disabled by
20118      * setting isTarget to false.
20119      * @method isTarget
20120      * @type boolean
20121      */
20122     isTarget: true,
20123
20124     /**
20125      * The padding configured for this drag and drop object for calculating
20126      * the drop zone intersection with this object.
20127      * @method padding
20128      * @type int[]
20129      */
20130     padding: null,
20131
20132     /**
20133      * Cached reference to the linked element
20134      * @property _domRef
20135      * @private
20136      */
20137     _domRef: null,
20138
20139     /**
20140      * Internal typeof flag
20141      * @property __ygDragDrop
20142      * @private
20143      */
20144     __ygDragDrop: true,
20145
20146     /**
20147      * Set to true when horizontal contraints are applied
20148      * @property constrainX
20149      * @type boolean
20150      * @private
20151      */
20152     constrainX: false,
20153
20154     /**
20155      * Set to true when vertical contraints are applied
20156      * @property constrainY
20157      * @type boolean
20158      * @private
20159      */
20160     constrainY: false,
20161
20162     /**
20163      * The left constraint
20164      * @property minX
20165      * @type int
20166      * @private
20167      */
20168     minX: 0,
20169
20170     /**
20171      * The right constraint
20172      * @property maxX
20173      * @type int
20174      * @private
20175      */
20176     maxX: 0,
20177
20178     /**
20179      * The up constraint
20180      * @property minY
20181      * @type int
20182      * @type int
20183      * @private
20184      */
20185     minY: 0,
20186
20187     /**
20188      * The down constraint
20189      * @property maxY
20190      * @type int
20191      * @private
20192      */
20193     maxY: 0,
20194
20195     /**
20196      * Maintain offsets when we resetconstraints.  Set to true when you want
20197      * the position of the element relative to its parent to stay the same
20198      * when the page changes
20199      *
20200      * @property maintainOffset
20201      * @type boolean
20202      */
20203     maintainOffset: false,
20204
20205     /**
20206      * Array of pixel locations the element will snap to if we specified a
20207      * horizontal graduation/interval.  This array is generated automatically
20208      * when you define a tick interval.
20209      * @property xTicks
20210      * @type int[]
20211      */
20212     xTicks: null,
20213
20214     /**
20215      * Array of pixel locations the element will snap to if we specified a
20216      * vertical graduation/interval.  This array is generated automatically
20217      * when you define a tick interval.
20218      * @property yTicks
20219      * @type int[]
20220      */
20221     yTicks: null,
20222
20223     /**
20224      * By default the drag and drop instance will only respond to the primary
20225      * button click (left button for a right-handed mouse).  Set to true to
20226      * allow drag and drop to start with any mouse click that is propogated
20227      * by the browser
20228      * @property primaryButtonOnly
20229      * @type boolean
20230      */
20231     primaryButtonOnly: true,
20232
20233     /**
20234      * The availabe property is false until the linked dom element is accessible.
20235      * @property available
20236      * @type boolean
20237      */
20238     available: false,
20239
20240     /**
20241      * By default, drags can only be initiated if the mousedown occurs in the
20242      * region the linked element is.  This is done in part to work around a
20243      * bug in some browsers that mis-report the mousedown if the previous
20244      * mouseup happened outside of the window.  This property is set to true
20245      * if outer handles are defined.
20246      *
20247      * @property hasOuterHandles
20248      * @type boolean
20249      * @default false
20250      */
20251     hasOuterHandles: false,
20252
20253     /**
20254      * Code that executes immediately before the startDrag event
20255      * @method b4StartDrag
20256      * @private
20257      */
20258     b4StartDrag: function(x, y) { },
20259
20260     /**
20261      * Abstract method called after a drag/drop object is clicked
20262      * and the drag or mousedown time thresholds have beeen met.
20263      * @method startDrag
20264      * @param {int} X click location
20265      * @param {int} Y click location
20266      */
20267     startDrag: function(x, y) { /* override this */ },
20268
20269     /**
20270      * Code that executes immediately before the onDrag event
20271      * @method b4Drag
20272      * @private
20273      */
20274     b4Drag: function(e) { },
20275
20276     /**
20277      * Abstract method called during the onMouseMove event while dragging an
20278      * object.
20279      * @method onDrag
20280      * @param {Event} e the mousemove event
20281      */
20282     onDrag: function(e) { /* override this */ },
20283
20284     /**
20285      * Abstract method called when this element fist begins hovering over
20286      * another DragDrop obj
20287      * @method onDragEnter
20288      * @param {Event} e the mousemove event
20289      * @param {String|DragDrop[]} id In POINT mode, the element
20290      * id this is hovering over.  In INTERSECT mode, an array of one or more
20291      * dragdrop items being hovered over.
20292      */
20293     onDragEnter: function(e, id) { /* override this */ },
20294
20295     /**
20296      * Code that executes immediately before the onDragOver event
20297      * @method b4DragOver
20298      * @private
20299      */
20300     b4DragOver: function(e) { },
20301
20302     /**
20303      * Abstract method called when this element is hovering over another
20304      * DragDrop obj
20305      * @method onDragOver
20306      * @param {Event} e the mousemove event
20307      * @param {String|DragDrop[]} id In POINT mode, the element
20308      * id this is hovering over.  In INTERSECT mode, an array of dd items
20309      * being hovered over.
20310      */
20311     onDragOver: function(e, id) { /* override this */ },
20312
20313     /**
20314      * Code that executes immediately before the onDragOut event
20315      * @method b4DragOut
20316      * @private
20317      */
20318     b4DragOut: function(e) { },
20319
20320     /**
20321      * Abstract method called when we are no longer hovering over an element
20322      * @method onDragOut
20323      * @param {Event} e the mousemove event
20324      * @param {String|DragDrop[]} id In POINT mode, the element
20325      * id this was hovering over.  In INTERSECT mode, an array of dd items
20326      * that the mouse is no longer over.
20327      */
20328     onDragOut: function(e, id) { /* override this */ },
20329
20330     /**
20331      * Code that executes immediately before the onDragDrop event
20332      * @method b4DragDrop
20333      * @private
20334      */
20335     b4DragDrop: function(e) { },
20336
20337     /**
20338      * Abstract method called when this item is dropped on another DragDrop
20339      * obj
20340      * @method onDragDrop
20341      * @param {Event} e the mouseup event
20342      * @param {String|DragDrop[]} id In POINT mode, the element
20343      * id this was dropped on.  In INTERSECT mode, an array of dd items this
20344      * was dropped on.
20345      */
20346     onDragDrop: function(e, id) { /* override this */ },
20347
20348     /**
20349      * Abstract method called when this item is dropped on an area with no
20350      * drop target
20351      * @method onInvalidDrop
20352      * @param {Event} e the mouseup event
20353      */
20354     onInvalidDrop: function(e) { /* override this */ },
20355
20356     /**
20357      * Code that executes immediately before the endDrag event
20358      * @method b4EndDrag
20359      * @private
20360      */
20361     b4EndDrag: function(e) { },
20362
20363     /**
20364      * Fired when we are done dragging the object
20365      * @method endDrag
20366      * @param {Event} e the mouseup event
20367      */
20368     endDrag: function(e) { /* override this */ },
20369
20370     /**
20371      * Code executed immediately before the onMouseDown event
20372      * @method b4MouseDown
20373      * @param {Event} e the mousedown event
20374      * @private
20375      */
20376     b4MouseDown: function(e) {  },
20377
20378     /**
20379      * Event handler that fires when a drag/drop obj gets a mousedown
20380      * @method onMouseDown
20381      * @param {Event} e the mousedown event
20382      */
20383     onMouseDown: function(e) { /* override this */ },
20384
20385     /**
20386      * Event handler that fires when a drag/drop obj gets a mouseup
20387      * @method onMouseUp
20388      * @param {Event} e the mouseup event
20389      */
20390     onMouseUp: function(e) { /* override this */ },
20391
20392     /**
20393      * Override the onAvailable method to do what is needed after the initial
20394      * position was determined.
20395      * @method onAvailable
20396      */
20397     onAvailable: function () {
20398     },
20399
20400     /*
20401      * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
20402      * @type Object
20403      */
20404     defaultPadding : {left:0, right:0, top:0, bottom:0},
20405
20406     /*
20407      * Initializes the drag drop object's constraints to restrict movement to a certain element.
20408  *
20409  * Usage:
20410  <pre><code>
20411  var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
20412                 { dragElId: "existingProxyDiv" });
20413  dd.startDrag = function(){
20414      this.constrainTo("parent-id");
20415  };
20416  </code></pre>
20417  * Or you can initalize it using the {@link Roo.Element} object:
20418  <pre><code>
20419  Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
20420      startDrag : function(){
20421          this.constrainTo("parent-id");
20422      }
20423  });
20424  </code></pre>
20425      * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
20426      * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
20427      * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
20428      * an object containing the sides to pad. For example: {right:10, bottom:10}
20429      * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
20430      */
20431     constrainTo : function(constrainTo, pad, inContent){
20432         if(typeof pad == "number"){
20433             pad = {left: pad, right:pad, top:pad, bottom:pad};
20434         }
20435         pad = pad || this.defaultPadding;
20436         var b = Roo.get(this.getEl()).getBox();
20437         var ce = Roo.get(constrainTo);
20438         var s = ce.getScroll();
20439         var c, cd = ce.dom;
20440         if(cd == document.body){
20441             c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
20442         }else{
20443             xy = ce.getXY();
20444             c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
20445         }
20446
20447
20448         var topSpace = b.y - c.y;
20449         var leftSpace = b.x - c.x;
20450
20451         this.resetConstraints();
20452         this.setXConstraint(leftSpace - (pad.left||0), // left
20453                 c.width - leftSpace - b.width - (pad.right||0) //right
20454         );
20455         this.setYConstraint(topSpace - (pad.top||0), //top
20456                 c.height - topSpace - b.height - (pad.bottom||0) //bottom
20457         );
20458     },
20459
20460     /**
20461      * Returns a reference to the linked element
20462      * @method getEl
20463      * @return {HTMLElement} the html element
20464      */
20465     getEl: function() {
20466         if (!this._domRef) {
20467             this._domRef = Roo.getDom(this.id);
20468         }
20469
20470         return this._domRef;
20471     },
20472
20473     /**
20474      * Returns a reference to the actual element to drag.  By default this is
20475      * the same as the html element, but it can be assigned to another
20476      * element. An example of this can be found in Roo.dd.DDProxy
20477      * @method getDragEl
20478      * @return {HTMLElement} the html element
20479      */
20480     getDragEl: function() {
20481         return Roo.getDom(this.dragElId);
20482     },
20483
20484     /**
20485      * Sets up the DragDrop object.  Must be called in the constructor of any
20486      * Roo.dd.DragDrop subclass
20487      * @method init
20488      * @param id the id of the linked element
20489      * @param {String} sGroup the group of related items
20490      * @param {object} config configuration attributes
20491      */
20492     init: function(id, sGroup, config) {
20493         this.initTarget(id, sGroup, config);
20494         if (!Roo.isTouch) {
20495             Event.on(this.id, "mousedown", this.handleMouseDown, this);
20496         }
20497         Event.on(this.id, "touchstart", this.handleMouseDown, this);
20498         // Event.on(this.id, "selectstart", Event.preventDefault);
20499     },
20500
20501     /**
20502      * Initializes Targeting functionality only... the object does not
20503      * get a mousedown handler.
20504      * @method initTarget
20505      * @param id the id of the linked element
20506      * @param {String} sGroup the group of related items
20507      * @param {object} config configuration attributes
20508      */
20509     initTarget: function(id, sGroup, config) {
20510
20511         // configuration attributes
20512         this.config = config || {};
20513
20514         // create a local reference to the drag and drop manager
20515         this.DDM = Roo.dd.DDM;
20516         // initialize the groups array
20517         this.groups = {};
20518
20519         // assume that we have an element reference instead of an id if the
20520         // parameter is not a string
20521         if (typeof id !== "string") {
20522             id = Roo.id(id);
20523         }
20524
20525         // set the id
20526         this.id = id;
20527
20528         // add to an interaction group
20529         this.addToGroup((sGroup) ? sGroup : "default");
20530
20531         // We don't want to register this as the handle with the manager
20532         // so we just set the id rather than calling the setter.
20533         this.handleElId = id;
20534
20535         // the linked element is the element that gets dragged by default
20536         this.setDragElId(id);
20537
20538         // by default, clicked anchors will not start drag operations.
20539         this.invalidHandleTypes = { A: "A" };
20540         this.invalidHandleIds = {};
20541         this.invalidHandleClasses = [];
20542
20543         this.applyConfig();
20544
20545         this.handleOnAvailable();
20546     },
20547
20548     /**
20549      * Applies the configuration parameters that were passed into the constructor.
20550      * This is supposed to happen at each level through the inheritance chain.  So
20551      * a DDProxy implentation will execute apply config on DDProxy, DD, and
20552      * DragDrop in order to get all of the parameters that are available in
20553      * each object.
20554      * @method applyConfig
20555      */
20556     applyConfig: function() {
20557
20558         // configurable properties:
20559         //    padding, isTarget, maintainOffset, primaryButtonOnly
20560         this.padding           = this.config.padding || [0, 0, 0, 0];
20561         this.isTarget          = (this.config.isTarget !== false);
20562         this.maintainOffset    = (this.config.maintainOffset);
20563         this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
20564
20565     },
20566
20567     /**
20568      * Executed when the linked element is available
20569      * @method handleOnAvailable
20570      * @private
20571      */
20572     handleOnAvailable: function() {
20573         this.available = true;
20574         this.resetConstraints();
20575         this.onAvailable();
20576     },
20577
20578      /**
20579      * Configures the padding for the target zone in px.  Effectively expands
20580      * (or reduces) the virtual object size for targeting calculations.
20581      * Supports css-style shorthand; if only one parameter is passed, all sides
20582      * will have that padding, and if only two are passed, the top and bottom
20583      * will have the first param, the left and right the second.
20584      * @method setPadding
20585      * @param {int} iTop    Top pad
20586      * @param {int} iRight  Right pad
20587      * @param {int} iBot    Bot pad
20588      * @param {int} iLeft   Left pad
20589      */
20590     setPadding: function(iTop, iRight, iBot, iLeft) {
20591         // this.padding = [iLeft, iRight, iTop, iBot];
20592         if (!iRight && 0 !== iRight) {
20593             this.padding = [iTop, iTop, iTop, iTop];
20594         } else if (!iBot && 0 !== iBot) {
20595             this.padding = [iTop, iRight, iTop, iRight];
20596         } else {
20597             this.padding = [iTop, iRight, iBot, iLeft];
20598         }
20599     },
20600
20601     /**
20602      * Stores the initial placement of the linked element.
20603      * @method setInitialPosition
20604      * @param {int} diffX   the X offset, default 0
20605      * @param {int} diffY   the Y offset, default 0
20606      */
20607     setInitPosition: function(diffX, diffY) {
20608         var el = this.getEl();
20609
20610         if (!this.DDM.verifyEl(el)) {
20611             return;
20612         }
20613
20614         var dx = diffX || 0;
20615         var dy = diffY || 0;
20616
20617         var p = Dom.getXY( el );
20618
20619         this.initPageX = p[0] - dx;
20620         this.initPageY = p[1] - dy;
20621
20622         this.lastPageX = p[0];
20623         this.lastPageY = p[1];
20624
20625
20626         this.setStartPosition(p);
20627     },
20628
20629     /**
20630      * Sets the start position of the element.  This is set when the obj
20631      * is initialized, the reset when a drag is started.
20632      * @method setStartPosition
20633      * @param pos current position (from previous lookup)
20634      * @private
20635      */
20636     setStartPosition: function(pos) {
20637         var p = pos || Dom.getXY( this.getEl() );
20638         this.deltaSetXY = null;
20639
20640         this.startPageX = p[0];
20641         this.startPageY = p[1];
20642     },
20643
20644     /**
20645      * Add this instance to a group of related drag/drop objects.  All
20646      * instances belong to at least one group, and can belong to as many
20647      * groups as needed.
20648      * @method addToGroup
20649      * @param sGroup {string} the name of the group
20650      */
20651     addToGroup: function(sGroup) {
20652         this.groups[sGroup] = true;
20653         this.DDM.regDragDrop(this, sGroup);
20654     },
20655
20656     /**
20657      * Remove's this instance from the supplied interaction group
20658      * @method removeFromGroup
20659      * @param {string}  sGroup  The group to drop
20660      */
20661     removeFromGroup: function(sGroup) {
20662         if (this.groups[sGroup]) {
20663             delete this.groups[sGroup];
20664         }
20665
20666         this.DDM.removeDDFromGroup(this, sGroup);
20667     },
20668
20669     /**
20670      * Allows you to specify that an element other than the linked element
20671      * will be moved with the cursor during a drag
20672      * @method setDragElId
20673      * @param id {string} the id of the element that will be used to initiate the drag
20674      */
20675     setDragElId: function(id) {
20676         this.dragElId = id;
20677     },
20678
20679     /**
20680      * Allows you to specify a child of the linked element that should be
20681      * used to initiate the drag operation.  An example of this would be if
20682      * you have a content div with text and links.  Clicking anywhere in the
20683      * content area would normally start the drag operation.  Use this method
20684      * to specify that an element inside of the content div is the element
20685      * that starts the drag operation.
20686      * @method setHandleElId
20687      * @param id {string} the id of the element that will be used to
20688      * initiate the drag.
20689      */
20690     setHandleElId: function(id) {
20691         if (typeof id !== "string") {
20692             id = Roo.id(id);
20693         }
20694         this.handleElId = id;
20695         this.DDM.regHandle(this.id, id);
20696     },
20697
20698     /**
20699      * Allows you to set an element outside of the linked element as a drag
20700      * handle
20701      * @method setOuterHandleElId
20702      * @param id the id of the element that will be used to initiate the drag
20703      */
20704     setOuterHandleElId: function(id) {
20705         if (typeof id !== "string") {
20706             id = Roo.id(id);
20707         }
20708         Event.on(id, "mousedown",
20709                 this.handleMouseDown, this);
20710         this.setHandleElId(id);
20711
20712         this.hasOuterHandles = true;
20713     },
20714
20715     /**
20716      * Remove all drag and drop hooks for this element
20717      * @method unreg
20718      */
20719     unreg: function() {
20720         Event.un(this.id, "mousedown",
20721                 this.handleMouseDown);
20722         Event.un(this.id, "touchstart",
20723                 this.handleMouseDown);
20724         this._domRef = null;
20725         this.DDM._remove(this);
20726     },
20727
20728     destroy : function(){
20729         this.unreg();
20730     },
20731
20732     /**
20733      * Returns true if this instance is locked, or the drag drop mgr is locked
20734      * (meaning that all drag/drop is disabled on the page.)
20735      * @method isLocked
20736      * @return {boolean} true if this obj or all drag/drop is locked, else
20737      * false
20738      */
20739     isLocked: function() {
20740         return (this.DDM.isLocked() || this.locked);
20741     },
20742
20743     /**
20744      * Fired when this object is clicked
20745      * @method handleMouseDown
20746      * @param {Event} e
20747      * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
20748      * @private
20749      */
20750     handleMouseDown: function(e, oDD){
20751      
20752         if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
20753             //Roo.log('not touch/ button !=0');
20754             return;
20755         }
20756         if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
20757             return; // double touch..
20758         }
20759         
20760
20761         if (this.isLocked()) {
20762             //Roo.log('locked');
20763             return;
20764         }
20765
20766         this.DDM.refreshCache(this.groups);
20767 //        Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
20768         var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
20769         if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) )  {
20770             //Roo.log('no outer handes or not over target');
20771                 // do nothing.
20772         } else {
20773 //            Roo.log('check validator');
20774             if (this.clickValidator(e)) {
20775 //                Roo.log('validate success');
20776                 // set the initial element position
20777                 this.setStartPosition();
20778
20779
20780                 this.b4MouseDown(e);
20781                 this.onMouseDown(e);
20782
20783                 this.DDM.handleMouseDown(e, this);
20784
20785                 this.DDM.stopEvent(e);
20786             } else {
20787
20788
20789             }
20790         }
20791     },
20792
20793     clickValidator: function(e) {
20794         var target = e.getTarget();
20795         return ( this.isValidHandleChild(target) &&
20796                     (this.id == this.handleElId ||
20797                         this.DDM.handleWasClicked(target, this.id)) );
20798     },
20799
20800     /**
20801      * Allows you to specify a tag name that should not start a drag operation
20802      * when clicked.  This is designed to facilitate embedding links within a
20803      * drag handle that do something other than start the drag.
20804      * @method addInvalidHandleType
20805      * @param {string} tagName the type of element to exclude
20806      */
20807     addInvalidHandleType: function(tagName) {
20808         var type = tagName.toUpperCase();
20809         this.invalidHandleTypes[type] = type;
20810     },
20811
20812     /**
20813      * Lets you to specify an element id for a child of a drag handle
20814      * that should not initiate a drag
20815      * @method addInvalidHandleId
20816      * @param {string} id the element id of the element you wish to ignore
20817      */
20818     addInvalidHandleId: function(id) {
20819         if (typeof id !== "string") {
20820             id = Roo.id(id);
20821         }
20822         this.invalidHandleIds[id] = id;
20823     },
20824
20825     /**
20826      * Lets you specify a css class of elements that will not initiate a drag
20827      * @method addInvalidHandleClass
20828      * @param {string} cssClass the class of the elements you wish to ignore
20829      */
20830     addInvalidHandleClass: function(cssClass) {
20831         this.invalidHandleClasses.push(cssClass);
20832     },
20833
20834     /**
20835      * Unsets an excluded tag name set by addInvalidHandleType
20836      * @method removeInvalidHandleType
20837      * @param {string} tagName the type of element to unexclude
20838      */
20839     removeInvalidHandleType: function(tagName) {
20840         var type = tagName.toUpperCase();
20841         // this.invalidHandleTypes[type] = null;
20842         delete this.invalidHandleTypes[type];
20843     },
20844
20845     /**
20846      * Unsets an invalid handle id
20847      * @method removeInvalidHandleId
20848      * @param {string} id the id of the element to re-enable
20849      */
20850     removeInvalidHandleId: function(id) {
20851         if (typeof id !== "string") {
20852             id = Roo.id(id);
20853         }
20854         delete this.invalidHandleIds[id];
20855     },
20856
20857     /**
20858      * Unsets an invalid css class
20859      * @method removeInvalidHandleClass
20860      * @param {string} cssClass the class of the element(s) you wish to
20861      * re-enable
20862      */
20863     removeInvalidHandleClass: function(cssClass) {
20864         for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
20865             if (this.invalidHandleClasses[i] == cssClass) {
20866                 delete this.invalidHandleClasses[i];
20867             }
20868         }
20869     },
20870
20871     /**
20872      * Checks the tag exclusion list to see if this click should be ignored
20873      * @method isValidHandleChild
20874      * @param {HTMLElement} node the HTMLElement to evaluate
20875      * @return {boolean} true if this is a valid tag type, false if not
20876      */
20877     isValidHandleChild: function(node) {
20878
20879         var valid = true;
20880         // var n = (node.nodeName == "#text") ? node.parentNode : node;
20881         var nodeName;
20882         try {
20883             nodeName = node.nodeName.toUpperCase();
20884         } catch(e) {
20885             nodeName = node.nodeName;
20886         }
20887         valid = valid && !this.invalidHandleTypes[nodeName];
20888         valid = valid && !this.invalidHandleIds[node.id];
20889
20890         for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
20891             valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
20892         }
20893
20894
20895         return valid;
20896
20897     },
20898
20899     /**
20900      * Create the array of horizontal tick marks if an interval was specified
20901      * in setXConstraint().
20902      * @method setXTicks
20903      * @private
20904      */
20905     setXTicks: function(iStartX, iTickSize) {
20906         this.xTicks = [];
20907         this.xTickSize = iTickSize;
20908
20909         var tickMap = {};
20910
20911         for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
20912             if (!tickMap[i]) {
20913                 this.xTicks[this.xTicks.length] = i;
20914                 tickMap[i] = true;
20915             }
20916         }
20917
20918         for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
20919             if (!tickMap[i]) {
20920                 this.xTicks[this.xTicks.length] = i;
20921                 tickMap[i] = true;
20922             }
20923         }
20924
20925         this.xTicks.sort(this.DDM.numericSort) ;
20926     },
20927
20928     /**
20929      * Create the array of vertical tick marks if an interval was specified in
20930      * setYConstraint().
20931      * @method setYTicks
20932      * @private
20933      */
20934     setYTicks: function(iStartY, iTickSize) {
20935         this.yTicks = [];
20936         this.yTickSize = iTickSize;
20937
20938         var tickMap = {};
20939
20940         for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
20941             if (!tickMap[i]) {
20942                 this.yTicks[this.yTicks.length] = i;
20943                 tickMap[i] = true;
20944             }
20945         }
20946
20947         for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
20948             if (!tickMap[i]) {
20949                 this.yTicks[this.yTicks.length] = i;
20950                 tickMap[i] = true;
20951             }
20952         }
20953
20954         this.yTicks.sort(this.DDM.numericSort) ;
20955     },
20956
20957     /**
20958      * By default, the element can be dragged any place on the screen.  Use
20959      * this method to limit the horizontal travel of the element.  Pass in
20960      * 0,0 for the parameters if you want to lock the drag to the y axis.
20961      * @method setXConstraint
20962      * @param {int} iLeft the number of pixels the element can move to the left
20963      * @param {int} iRight the number of pixels the element can move to the
20964      * right
20965      * @param {int} iTickSize optional parameter for specifying that the
20966      * element
20967      * should move iTickSize pixels at a time.
20968      */
20969     setXConstraint: function(iLeft, iRight, iTickSize) {
20970         this.leftConstraint = iLeft;
20971         this.rightConstraint = iRight;
20972
20973         this.minX = this.initPageX - iLeft;
20974         this.maxX = this.initPageX + iRight;
20975         if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
20976
20977         this.constrainX = true;
20978     },
20979
20980     /**
20981      * Clears any constraints applied to this instance.  Also clears ticks
20982      * since they can't exist independent of a constraint at this time.
20983      * @method clearConstraints
20984      */
20985     clearConstraints: function() {
20986         this.constrainX = false;
20987         this.constrainY = false;
20988         this.clearTicks();
20989     },
20990
20991     /**
20992      * Clears any tick interval defined for this instance
20993      * @method clearTicks
20994      */
20995     clearTicks: function() {
20996         this.xTicks = null;
20997         this.yTicks = null;
20998         this.xTickSize = 0;
20999         this.yTickSize = 0;
21000     },
21001
21002     /**
21003      * By default, the element can be dragged any place on the screen.  Set
21004      * this to limit the vertical travel of the element.  Pass in 0,0 for the
21005      * parameters if you want to lock the drag to the x axis.
21006      * @method setYConstraint
21007      * @param {int} iUp the number of pixels the element can move up
21008      * @param {int} iDown the number of pixels the element can move down
21009      * @param {int} iTickSize optional parameter for specifying that the
21010      * element should move iTickSize pixels at a time.
21011      */
21012     setYConstraint: function(iUp, iDown, iTickSize) {
21013         this.topConstraint = iUp;
21014         this.bottomConstraint = iDown;
21015
21016         this.minY = this.initPageY - iUp;
21017         this.maxY = this.initPageY + iDown;
21018         if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
21019
21020         this.constrainY = true;
21021
21022     },
21023
21024     /**
21025      * resetConstraints must be called if you manually reposition a dd element.
21026      * @method resetConstraints
21027      * @param {boolean} maintainOffset
21028      */
21029     resetConstraints: function() {
21030
21031
21032         // Maintain offsets if necessary
21033         if (this.initPageX || this.initPageX === 0) {
21034             // figure out how much this thing has moved
21035             var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
21036             var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
21037
21038             this.setInitPosition(dx, dy);
21039
21040         // This is the first time we have detected the element's position
21041         } else {
21042             this.setInitPosition();
21043         }
21044
21045         if (this.constrainX) {
21046             this.setXConstraint( this.leftConstraint,
21047                                  this.rightConstraint,
21048                                  this.xTickSize        );
21049         }
21050
21051         if (this.constrainY) {
21052             this.setYConstraint( this.topConstraint,
21053                                  this.bottomConstraint,
21054                                  this.yTickSize         );
21055         }
21056     },
21057
21058     /**
21059      * Normally the drag element is moved pixel by pixel, but we can specify
21060      * that it move a number of pixels at a time.  This method resolves the
21061      * location when we have it set up like this.
21062      * @method getTick
21063      * @param {int} val where we want to place the object
21064      * @param {int[]} tickArray sorted array of valid points
21065      * @return {int} the closest tick
21066      * @private
21067      */
21068     getTick: function(val, tickArray) {
21069
21070         if (!tickArray) {
21071             // If tick interval is not defined, it is effectively 1 pixel,
21072             // so we return the value passed to us.
21073             return val;
21074         } else if (tickArray[0] >= val) {
21075             // The value is lower than the first tick, so we return the first
21076             // tick.
21077             return tickArray[0];
21078         } else {
21079             for (var i=0, len=tickArray.length; i<len; ++i) {
21080                 var next = i + 1;
21081                 if (tickArray[next] && tickArray[next] >= val) {
21082                     var diff1 = val - tickArray[i];
21083                     var diff2 = tickArray[next] - val;
21084                     return (diff2 > diff1) ? tickArray[i] : tickArray[next];
21085                 }
21086             }
21087
21088             // The value is larger than the last tick, so we return the last
21089             // tick.
21090             return tickArray[tickArray.length - 1];
21091         }
21092     },
21093
21094     /**
21095      * toString method
21096      * @method toString
21097      * @return {string} string representation of the dd obj
21098      */
21099     toString: function() {
21100         return ("DragDrop " + this.id);
21101     }
21102
21103 });
21104
21105 })();
21106 /*
21107  * Based on:
21108  * Ext JS Library 1.1.1
21109  * Copyright(c) 2006-2007, Ext JS, LLC.
21110  *
21111  * Originally Released Under LGPL - original licence link has changed is not relivant.
21112  *
21113  * Fork - LGPL
21114  * <script type="text/javascript">
21115  */
21116
21117
21118 /**
21119  * The drag and drop utility provides a framework for building drag and drop
21120  * applications.  In addition to enabling drag and drop for specific elements,
21121  * the drag and drop elements are tracked by the manager class, and the
21122  * interactions between the various elements are tracked during the drag and
21123  * the implementing code is notified about these important moments.
21124  */
21125
21126 // Only load the library once.  Rewriting the manager class would orphan
21127 // existing drag and drop instances.
21128 if (!Roo.dd.DragDropMgr) {
21129
21130 /**
21131  * @class Roo.dd.DragDropMgr
21132  * DragDropMgr is a singleton that tracks the element interaction for
21133  * all DragDrop items in the window.  Generally, you will not call
21134  * this class directly, but it does have helper methods that could
21135  * be useful in your DragDrop implementations.
21136  * @static
21137  */
21138 Roo.dd.DragDropMgr = function() {
21139
21140     var Event = Roo.EventManager;
21141
21142     return {
21143
21144         /**
21145          * Two dimensional Array of registered DragDrop objects.  The first
21146          * dimension is the DragDrop item group, the second the DragDrop
21147          * object.
21148          * @property ids
21149          * @type {string: string}
21150          * @private
21151          * @static
21152          */
21153         ids: {},
21154
21155         /**
21156          * Array of element ids defined as drag handles.  Used to determine
21157          * if the element that generated the mousedown event is actually the
21158          * handle and not the html element itself.
21159          * @property handleIds
21160          * @type {string: string}
21161          * @private
21162          * @static
21163          */
21164         handleIds: {},
21165
21166         /**
21167          * the DragDrop object that is currently being dragged
21168          * @property dragCurrent
21169          * @type DragDrop
21170          * @private
21171          * @static
21172          **/
21173         dragCurrent: null,
21174
21175         /**
21176          * the DragDrop object(s) that are being hovered over
21177          * @property dragOvers
21178          * @type Array
21179          * @private
21180          * @static
21181          */
21182         dragOvers: {},
21183
21184         /**
21185          * the X distance between the cursor and the object being dragged
21186          * @property deltaX
21187          * @type int
21188          * @private
21189          * @static
21190          */
21191         deltaX: 0,
21192
21193         /**
21194          * the Y distance between the cursor and the object being dragged
21195          * @property deltaY
21196          * @type int
21197          * @private
21198          * @static
21199          */
21200         deltaY: 0,
21201
21202         /**
21203          * Flag to determine if we should prevent the default behavior of the
21204          * events we define. By default this is true, but this can be set to
21205          * false if you need the default behavior (not recommended)
21206          * @property preventDefault
21207          * @type boolean
21208          * @static
21209          */
21210         preventDefault: true,
21211
21212         /**
21213          * Flag to determine if we should stop the propagation of the events
21214          * we generate. This is true by default but you may want to set it to
21215          * false if the html element contains other features that require the
21216          * mouse click.
21217          * @property stopPropagation
21218          * @type boolean
21219          * @static
21220          */
21221         stopPropagation: true,
21222
21223         /**
21224          * Internal flag that is set to true when drag and drop has been
21225          * intialized
21226          * @property initialized
21227          * @private
21228          * @static
21229          */
21230         initalized: false,
21231
21232         /**
21233          * All drag and drop can be disabled.
21234          * @property locked
21235          * @private
21236          * @static
21237          */
21238         locked: false,
21239
21240         /**
21241          * Called the first time an element is registered.
21242          * @method init
21243          * @private
21244          * @static
21245          */
21246         init: function() {
21247             this.initialized = true;
21248         },
21249
21250         /**
21251          * In point mode, drag and drop interaction is defined by the
21252          * location of the cursor during the drag/drop
21253          * @property POINT
21254          * @type int
21255          * @static
21256          */
21257         POINT: 0,
21258
21259         /**
21260          * In intersect mode, drag and drop interactio nis defined by the
21261          * overlap of two or more drag and drop objects.
21262          * @property INTERSECT
21263          * @type int
21264          * @static
21265          */
21266         INTERSECT: 1,
21267
21268         /**
21269          * The current drag and drop mode.  Default: POINT
21270          * @property mode
21271          * @type int
21272          * @static
21273          */
21274         mode: 0,
21275
21276         /**
21277          * Runs method on all drag and drop objects
21278          * @method _execOnAll
21279          * @private
21280          * @static
21281          */
21282         _execOnAll: function(sMethod, args) {
21283             for (var i in this.ids) {
21284                 for (var j in this.ids[i]) {
21285                     var oDD = this.ids[i][j];
21286                     if (! this.isTypeOfDD(oDD)) {
21287                         continue;
21288                     }
21289                     oDD[sMethod].apply(oDD, args);
21290                 }
21291             }
21292         },
21293
21294         /**
21295          * Drag and drop initialization.  Sets up the global event handlers
21296          * @method _onLoad
21297          * @private
21298          * @static
21299          */
21300         _onLoad: function() {
21301
21302             this.init();
21303
21304             if (!Roo.isTouch) {
21305                 Event.on(document, "mouseup",   this.handleMouseUp, this, true);
21306                 Event.on(document, "mousemove", this.handleMouseMove, this, true);
21307             }
21308             Event.on(document, "touchend",   this.handleMouseUp, this, true);
21309             Event.on(document, "touchmove", this.handleMouseMove, this, true);
21310             
21311             Event.on(window,   "unload",    this._onUnload, this, true);
21312             Event.on(window,   "resize",    this._onResize, this, true);
21313             // Event.on(window,   "mouseout",    this._test);
21314
21315         },
21316
21317         /**
21318          * Reset constraints on all drag and drop objs
21319          * @method _onResize
21320          * @private
21321          * @static
21322          */
21323         _onResize: function(e) {
21324             this._execOnAll("resetConstraints", []);
21325         },
21326
21327         /**
21328          * Lock all drag and drop functionality
21329          * @method lock
21330          * @static
21331          */
21332         lock: function() { this.locked = true; },
21333
21334         /**
21335          * Unlock all drag and drop functionality
21336          * @method unlock
21337          * @static
21338          */
21339         unlock: function() { this.locked = false; },
21340
21341         /**
21342          * Is drag and drop locked?
21343          * @method isLocked
21344          * @return {boolean} True if drag and drop is locked, false otherwise.
21345          * @static
21346          */
21347         isLocked: function() { return this.locked; },
21348
21349         /**
21350          * Location cache that is set for all drag drop objects when a drag is
21351          * initiated, cleared when the drag is finished.
21352          * @property locationCache
21353          * @private
21354          * @static
21355          */
21356         locationCache: {},
21357
21358         /**
21359          * Set useCache to false if you want to force object the lookup of each
21360          * drag and drop linked element constantly during a drag.
21361          * @property useCache
21362          * @type boolean
21363          * @static
21364          */
21365         useCache: true,
21366
21367         /**
21368          * The number of pixels that the mouse needs to move after the
21369          * mousedown before the drag is initiated.  Default=3;
21370          * @property clickPixelThresh
21371          * @type int
21372          * @static
21373          */
21374         clickPixelThresh: 3,
21375
21376         /**
21377          * The number of milliseconds after the mousedown event to initiate the
21378          * drag if we don't get a mouseup event. Default=1000
21379          * @property clickTimeThresh
21380          * @type int
21381          * @static
21382          */
21383         clickTimeThresh: 350,
21384
21385         /**
21386          * Flag that indicates that either the drag pixel threshold or the
21387          * mousdown time threshold has been met
21388          * @property dragThreshMet
21389          * @type boolean
21390          * @private
21391          * @static
21392          */
21393         dragThreshMet: false,
21394
21395         /**
21396          * Timeout used for the click time threshold
21397          * @property clickTimeout
21398          * @type Object
21399          * @private
21400          * @static
21401          */
21402         clickTimeout: null,
21403
21404         /**
21405          * The X position of the mousedown event stored for later use when a
21406          * drag threshold is met.
21407          * @property startX
21408          * @type int
21409          * @private
21410          * @static
21411          */
21412         startX: 0,
21413
21414         /**
21415          * The Y position of the mousedown event stored for later use when a
21416          * drag threshold is met.
21417          * @property startY
21418          * @type int
21419          * @private
21420          * @static
21421          */
21422         startY: 0,
21423
21424         /**
21425          * Each DragDrop instance must be registered with the DragDropMgr.
21426          * This is executed in DragDrop.init()
21427          * @method regDragDrop
21428          * @param {DragDrop} oDD the DragDrop object to register
21429          * @param {String} sGroup the name of the group this element belongs to
21430          * @static
21431          */
21432         regDragDrop: function(oDD, sGroup) {
21433             if (!this.initialized) { this.init(); }
21434
21435             if (!this.ids[sGroup]) {
21436                 this.ids[sGroup] = {};
21437             }
21438             this.ids[sGroup][oDD.id] = oDD;
21439         },
21440
21441         /**
21442          * Removes the supplied dd instance from the supplied group. Executed
21443          * by DragDrop.removeFromGroup, so don't call this function directly.
21444          * @method removeDDFromGroup
21445          * @private
21446          * @static
21447          */
21448         removeDDFromGroup: function(oDD, sGroup) {
21449             if (!this.ids[sGroup]) {
21450                 this.ids[sGroup] = {};
21451             }
21452
21453             var obj = this.ids[sGroup];
21454             if (obj && obj[oDD.id]) {
21455                 delete obj[oDD.id];
21456             }
21457         },
21458
21459         /**
21460          * Unregisters a drag and drop item.  This is executed in
21461          * DragDrop.unreg, use that method instead of calling this directly.
21462          * @method _remove
21463          * @private
21464          * @static
21465          */
21466         _remove: function(oDD) {
21467             for (var g in oDD.groups) {
21468                 if (g && this.ids[g][oDD.id]) {
21469                     delete this.ids[g][oDD.id];
21470                 }
21471             }
21472             delete this.handleIds[oDD.id];
21473         },
21474
21475         /**
21476          * Each DragDrop handle element must be registered.  This is done
21477          * automatically when executing DragDrop.setHandleElId()
21478          * @method regHandle
21479          * @param {String} sDDId the DragDrop id this element is a handle for
21480          * @param {String} sHandleId the id of the element that is the drag
21481          * handle
21482          * @static
21483          */
21484         regHandle: function(sDDId, sHandleId) {
21485             if (!this.handleIds[sDDId]) {
21486                 this.handleIds[sDDId] = {};
21487             }
21488             this.handleIds[sDDId][sHandleId] = sHandleId;
21489         },
21490
21491         /**
21492          * Utility function to determine if a given element has been
21493          * registered as a drag drop item.
21494          * @method isDragDrop
21495          * @param {String} id the element id to check
21496          * @return {boolean} true if this element is a DragDrop item,
21497          * false otherwise
21498          * @static
21499          */
21500         isDragDrop: function(id) {
21501             return ( this.getDDById(id) ) ? true : false;
21502         },
21503
21504         /**
21505          * Returns the drag and drop instances that are in all groups the
21506          * passed in instance belongs to.
21507          * @method getRelated
21508          * @param {DragDrop} p_oDD the obj to get related data for
21509          * @param {boolean} bTargetsOnly if true, only return targetable objs
21510          * @return {DragDrop[]} the related instances
21511          * @static
21512          */
21513         getRelated: function(p_oDD, bTargetsOnly) {
21514             var oDDs = [];
21515             for (var i in p_oDD.groups) {
21516                 for (j in this.ids[i]) {
21517                     var dd = this.ids[i][j];
21518                     if (! this.isTypeOfDD(dd)) {
21519                         continue;
21520                     }
21521                     if (!bTargetsOnly || dd.isTarget) {
21522                         oDDs[oDDs.length] = dd;
21523                     }
21524                 }
21525             }
21526
21527             return oDDs;
21528         },
21529
21530         /**
21531          * Returns true if the specified dd target is a legal target for
21532          * the specifice drag obj
21533          * @method isLegalTarget
21534          * @param {DragDrop} the drag obj
21535          * @param {DragDrop} the target
21536          * @return {boolean} true if the target is a legal target for the
21537          * dd obj
21538          * @static
21539          */
21540         isLegalTarget: function (oDD, oTargetDD) {
21541             var targets = this.getRelated(oDD, true);
21542             for (var i=0, len=targets.length;i<len;++i) {
21543                 if (targets[i].id == oTargetDD.id) {
21544                     return true;
21545                 }
21546             }
21547
21548             return false;
21549         },
21550
21551         /**
21552          * My goal is to be able to transparently determine if an object is
21553          * typeof DragDrop, and the exact subclass of DragDrop.  typeof
21554          * returns "object", oDD.constructor.toString() always returns
21555          * "DragDrop" and not the name of the subclass.  So for now it just
21556          * evaluates a well-known variable in DragDrop.
21557          * @method isTypeOfDD
21558          * @param {Object} the object to evaluate
21559          * @return {boolean} true if typeof oDD = DragDrop
21560          * @static
21561          */
21562         isTypeOfDD: function (oDD) {
21563             return (oDD && oDD.__ygDragDrop);
21564         },
21565
21566         /**
21567          * Utility function to determine if a given element has been
21568          * registered as a drag drop handle for the given Drag Drop object.
21569          * @method isHandle
21570          * @param {String} id the element id to check
21571          * @return {boolean} true if this element is a DragDrop handle, false
21572          * otherwise
21573          * @static
21574          */
21575         isHandle: function(sDDId, sHandleId) {
21576             return ( this.handleIds[sDDId] &&
21577                             this.handleIds[sDDId][sHandleId] );
21578         },
21579
21580         /**
21581          * Returns the DragDrop instance for a given id
21582          * @method getDDById
21583          * @param {String} id the id of the DragDrop object
21584          * @return {DragDrop} the drag drop object, null if it is not found
21585          * @static
21586          */
21587         getDDById: function(id) {
21588             for (var i in this.ids) {
21589                 if (this.ids[i][id]) {
21590                     return this.ids[i][id];
21591                 }
21592             }
21593             return null;
21594         },
21595
21596         /**
21597          * Fired after a registered DragDrop object gets the mousedown event.
21598          * Sets up the events required to track the object being dragged
21599          * @method handleMouseDown
21600          * @param {Event} e the event
21601          * @param oDD the DragDrop object being dragged
21602          * @private
21603          * @static
21604          */
21605         handleMouseDown: function(e, oDD) {
21606             if(Roo.QuickTips){
21607                 Roo.QuickTips.disable();
21608             }
21609             this.currentTarget = e.getTarget();
21610
21611             this.dragCurrent = oDD;
21612
21613             var el = oDD.getEl();
21614
21615             // track start position
21616             this.startX = e.getPageX();
21617             this.startY = e.getPageY();
21618
21619             this.deltaX = this.startX - el.offsetLeft;
21620             this.deltaY = this.startY - el.offsetTop;
21621
21622             this.dragThreshMet = false;
21623
21624             this.clickTimeout = setTimeout(
21625                     function() {
21626                         var DDM = Roo.dd.DDM;
21627                         DDM.startDrag(DDM.startX, DDM.startY);
21628                     },
21629                     this.clickTimeThresh );
21630         },
21631
21632         /**
21633          * Fired when either the drag pixel threshol or the mousedown hold
21634          * time threshold has been met.
21635          * @method startDrag
21636          * @param x {int} the X position of the original mousedown
21637          * @param y {int} the Y position of the original mousedown
21638          * @static
21639          */
21640         startDrag: function(x, y) {
21641             clearTimeout(this.clickTimeout);
21642             if (this.dragCurrent) {
21643                 this.dragCurrent.b4StartDrag(x, y);
21644                 this.dragCurrent.startDrag(x, y);
21645             }
21646             this.dragThreshMet = true;
21647         },
21648
21649         /**
21650          * Internal function to handle the mouseup event.  Will be invoked
21651          * from the context of the document.
21652          * @method handleMouseUp
21653          * @param {Event} e the event
21654          * @private
21655          * @static
21656          */
21657         handleMouseUp: function(e) {
21658
21659             if(Roo.QuickTips){
21660                 Roo.QuickTips.enable();
21661             }
21662             if (! this.dragCurrent) {
21663                 return;
21664             }
21665
21666             clearTimeout(this.clickTimeout);
21667
21668             if (this.dragThreshMet) {
21669                 this.fireEvents(e, true);
21670             } else {
21671             }
21672
21673             this.stopDrag(e);
21674
21675             this.stopEvent(e);
21676         },
21677
21678         /**
21679          * Utility to stop event propagation and event default, if these
21680          * features are turned on.
21681          * @method stopEvent
21682          * @param {Event} e the event as returned by this.getEvent()
21683          * @static
21684          */
21685         stopEvent: function(e){
21686             if(this.stopPropagation) {
21687                 e.stopPropagation();
21688             }
21689
21690             if (this.preventDefault) {
21691                 e.preventDefault();
21692             }
21693         },
21694
21695         /**
21696          * Internal function to clean up event handlers after the drag
21697          * operation is complete
21698          * @method stopDrag
21699          * @param {Event} e the event
21700          * @private
21701          * @static
21702          */
21703         stopDrag: function(e) {
21704             // Fire the drag end event for the item that was dragged
21705             if (this.dragCurrent) {
21706                 if (this.dragThreshMet) {
21707                     this.dragCurrent.b4EndDrag(e);
21708                     this.dragCurrent.endDrag(e);
21709                 }
21710
21711                 this.dragCurrent.onMouseUp(e);
21712             }
21713
21714             this.dragCurrent = null;
21715             this.dragOvers = {};
21716         },
21717
21718         /**
21719          * Internal function to handle the mousemove event.  Will be invoked
21720          * from the context of the html element.
21721          *
21722          * @TODO figure out what we can do about mouse events lost when the
21723          * user drags objects beyond the window boundary.  Currently we can
21724          * detect this in internet explorer by verifying that the mouse is
21725          * down during the mousemove event.  Firefox doesn't give us the
21726          * button state on the mousemove event.
21727          * @method handleMouseMove
21728          * @param {Event} e the event
21729          * @private
21730          * @static
21731          */
21732         handleMouseMove: function(e) {
21733             if (! this.dragCurrent) {
21734                 return true;
21735             }
21736
21737             // var button = e.which || e.button;
21738
21739             // check for IE mouseup outside of page boundary
21740             if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
21741                 this.stopEvent(e);
21742                 return this.handleMouseUp(e);
21743             }
21744
21745             if (!this.dragThreshMet) {
21746                 var diffX = Math.abs(this.startX - e.getPageX());
21747                 var diffY = Math.abs(this.startY - e.getPageY());
21748                 if (diffX > this.clickPixelThresh ||
21749                             diffY > this.clickPixelThresh) {
21750                     this.startDrag(this.startX, this.startY);
21751                 }
21752             }
21753
21754             if (this.dragThreshMet) {
21755                 this.dragCurrent.b4Drag(e);
21756                 this.dragCurrent.onDrag(e);
21757                 if(!this.dragCurrent.moveOnly){
21758                     this.fireEvents(e, false);
21759                 }
21760             }
21761
21762             this.stopEvent(e);
21763
21764             return true;
21765         },
21766
21767         /**
21768          * Iterates over all of the DragDrop elements to find ones we are
21769          * hovering over or dropping on
21770          * @method fireEvents
21771          * @param {Event} e the event
21772          * @param {boolean} isDrop is this a drop op or a mouseover op?
21773          * @private
21774          * @static
21775          */
21776         fireEvents: function(e, isDrop) {
21777             var dc = this.dragCurrent;
21778
21779             // If the user did the mouse up outside of the window, we could
21780             // get here even though we have ended the drag.
21781             if (!dc || dc.isLocked()) {
21782                 return;
21783             }
21784
21785             var pt = e.getPoint();
21786
21787             // cache the previous dragOver array
21788             var oldOvers = [];
21789
21790             var outEvts   = [];
21791             var overEvts  = [];
21792             var dropEvts  = [];
21793             var enterEvts = [];
21794
21795             // Check to see if the object(s) we were hovering over is no longer
21796             // being hovered over so we can fire the onDragOut event
21797             for (var i in this.dragOvers) {
21798
21799                 var ddo = this.dragOvers[i];
21800
21801                 if (! this.isTypeOfDD(ddo)) {
21802                     continue;
21803                 }
21804
21805                 if (! this.isOverTarget(pt, ddo, this.mode)) {
21806                     outEvts.push( ddo );
21807                 }
21808
21809                 oldOvers[i] = true;
21810                 delete this.dragOvers[i];
21811             }
21812
21813             for (var sGroup in dc.groups) {
21814
21815                 if ("string" != typeof sGroup) {
21816                     continue;
21817                 }
21818
21819                 for (i in this.ids[sGroup]) {
21820                     var oDD = this.ids[sGroup][i];
21821                     if (! this.isTypeOfDD(oDD)) {
21822                         continue;
21823                     }
21824
21825                     if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
21826                         if (this.isOverTarget(pt, oDD, this.mode)) {
21827                             // look for drop interactions
21828                             if (isDrop) {
21829                                 dropEvts.push( oDD );
21830                             // look for drag enter and drag over interactions
21831                             } else {
21832
21833                                 // initial drag over: dragEnter fires
21834                                 if (!oldOvers[oDD.id]) {
21835                                     enterEvts.push( oDD );
21836                                 // subsequent drag overs: dragOver fires
21837                                 } else {
21838                                     overEvts.push( oDD );
21839                                 }
21840
21841                                 this.dragOvers[oDD.id] = oDD;
21842                             }
21843                         }
21844                     }
21845                 }
21846             }
21847
21848             if (this.mode) {
21849                 if (outEvts.length) {
21850                     dc.b4DragOut(e, outEvts);
21851                     dc.onDragOut(e, outEvts);
21852                 }
21853
21854                 if (enterEvts.length) {
21855                     dc.onDragEnter(e, enterEvts);
21856                 }
21857
21858                 if (overEvts.length) {
21859                     dc.b4DragOver(e, overEvts);
21860                     dc.onDragOver(e, overEvts);
21861                 }
21862
21863                 if (dropEvts.length) {
21864                     dc.b4DragDrop(e, dropEvts);
21865                     dc.onDragDrop(e, dropEvts);
21866                 }
21867
21868             } else {
21869                 // fire dragout events
21870                 var len = 0;
21871                 for (i=0, len=outEvts.length; i<len; ++i) {
21872                     dc.b4DragOut(e, outEvts[i].id);
21873                     dc.onDragOut(e, outEvts[i].id);
21874                 }
21875
21876                 // fire enter events
21877                 for (i=0,len=enterEvts.length; i<len; ++i) {
21878                     // dc.b4DragEnter(e, oDD.id);
21879                     dc.onDragEnter(e, enterEvts[i].id);
21880                 }
21881
21882                 // fire over events
21883                 for (i=0,len=overEvts.length; i<len; ++i) {
21884                     dc.b4DragOver(e, overEvts[i].id);
21885                     dc.onDragOver(e, overEvts[i].id);
21886                 }
21887
21888                 // fire drop events
21889                 for (i=0, len=dropEvts.length; i<len; ++i) {
21890                     dc.b4DragDrop(e, dropEvts[i].id);
21891                     dc.onDragDrop(e, dropEvts[i].id);
21892                 }
21893
21894             }
21895
21896             // notify about a drop that did not find a target
21897             if (isDrop && !dropEvts.length) {
21898                 dc.onInvalidDrop(e);
21899             }
21900
21901         },
21902
21903         /**
21904          * Helper function for getting the best match from the list of drag
21905          * and drop objects returned by the drag and drop events when we are
21906          * in INTERSECT mode.  It returns either the first object that the
21907          * cursor is over, or the object that has the greatest overlap with
21908          * the dragged element.
21909          * @method getBestMatch
21910          * @param  {DragDrop[]} dds The array of drag and drop objects
21911          * targeted
21912          * @return {DragDrop}       The best single match
21913          * @static
21914          */
21915         getBestMatch: function(dds) {
21916             var winner = null;
21917             // Return null if the input is not what we expect
21918             //if (!dds || !dds.length || dds.length == 0) {
21919                // winner = null;
21920             // If there is only one item, it wins
21921             //} else if (dds.length == 1) {
21922
21923             var len = dds.length;
21924
21925             if (len == 1) {
21926                 winner = dds[0];
21927             } else {
21928                 // Loop through the targeted items
21929                 for (var i=0; i<len; ++i) {
21930                     var dd = dds[i];
21931                     // If the cursor is over the object, it wins.  If the
21932                     // cursor is over multiple matches, the first one we come
21933                     // to wins.
21934                     if (dd.cursorIsOver) {
21935                         winner = dd;
21936                         break;
21937                     // Otherwise the object with the most overlap wins
21938                     } else {
21939                         if (!winner ||
21940                             winner.overlap.getArea() < dd.overlap.getArea()) {
21941                             winner = dd;
21942                         }
21943                     }
21944                 }
21945             }
21946
21947             return winner;
21948         },
21949
21950         /**
21951          * Refreshes the cache of the top-left and bottom-right points of the
21952          * drag and drop objects in the specified group(s).  This is in the
21953          * format that is stored in the drag and drop instance, so typical
21954          * usage is:
21955          * <code>
21956          * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
21957          * </code>
21958          * Alternatively:
21959          * <code>
21960          * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
21961          * </code>
21962          * @TODO this really should be an indexed array.  Alternatively this
21963          * method could accept both.
21964          * @method refreshCache
21965          * @param {Object} groups an associative array of groups to refresh
21966          * @static
21967          */
21968         refreshCache: function(groups) {
21969             for (var sGroup in groups) {
21970                 if ("string" != typeof sGroup) {
21971                     continue;
21972                 }
21973                 for (var i in this.ids[sGroup]) {
21974                     var oDD = this.ids[sGroup][i];
21975
21976                     if (this.isTypeOfDD(oDD)) {
21977                     // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
21978                         var loc = this.getLocation(oDD);
21979                         if (loc) {
21980                             this.locationCache[oDD.id] = loc;
21981                         } else {
21982                             delete this.locationCache[oDD.id];
21983                             // this will unregister the drag and drop object if
21984                             // the element is not in a usable state
21985                             // oDD.unreg();
21986                         }
21987                     }
21988                 }
21989             }
21990         },
21991
21992         /**
21993          * This checks to make sure an element exists and is in the DOM.  The
21994          * main purpose is to handle cases where innerHTML is used to remove
21995          * drag and drop objects from the DOM.  IE provides an 'unspecified
21996          * error' when trying to access the offsetParent of such an element
21997          * @method verifyEl
21998          * @param {HTMLElement} el the element to check
21999          * @return {boolean} true if the element looks usable
22000          * @static
22001          */
22002         verifyEl: function(el) {
22003             if (el) {
22004                 var parent;
22005                 if(Roo.isIE){
22006                     try{
22007                         parent = el.offsetParent;
22008                     }catch(e){}
22009                 }else{
22010                     parent = el.offsetParent;
22011                 }
22012                 if (parent) {
22013                     return true;
22014                 }
22015             }
22016
22017             return false;
22018         },
22019
22020         /**
22021          * Returns a Region object containing the drag and drop element's position
22022          * and size, including the padding configured for it
22023          * @method getLocation
22024          * @param {DragDrop} oDD the drag and drop object to get the
22025          *                       location for
22026          * @return {Roo.lib.Region} a Region object representing the total area
22027          *                             the element occupies, including any padding
22028          *                             the instance is configured for.
22029          * @static
22030          */
22031         getLocation: function(oDD) {
22032             if (! this.isTypeOfDD(oDD)) {
22033                 return null;
22034             }
22035
22036             var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
22037
22038             try {
22039                 pos= Roo.lib.Dom.getXY(el);
22040             } catch (e) { }
22041
22042             if (!pos) {
22043                 return null;
22044             }
22045
22046             x1 = pos[0];
22047             x2 = x1 + el.offsetWidth;
22048             y1 = pos[1];
22049             y2 = y1 + el.offsetHeight;
22050
22051             t = y1 - oDD.padding[0];
22052             r = x2 + oDD.padding[1];
22053             b = y2 + oDD.padding[2];
22054             l = x1 - oDD.padding[3];
22055
22056             return new Roo.lib.Region( t, r, b, l );
22057         },
22058
22059         /**
22060          * Checks the cursor location to see if it over the target
22061          * @method isOverTarget
22062          * @param {Roo.lib.Point} pt The point to evaluate
22063          * @param {DragDrop} oTarget the DragDrop object we are inspecting
22064          * @return {boolean} true if the mouse is over the target
22065          * @private
22066          * @static
22067          */
22068         isOverTarget: function(pt, oTarget, intersect) {
22069             // use cache if available
22070             var loc = this.locationCache[oTarget.id];
22071             if (!loc || !this.useCache) {
22072                 loc = this.getLocation(oTarget);
22073                 this.locationCache[oTarget.id] = loc;
22074
22075             }
22076
22077             if (!loc) {
22078                 return false;
22079             }
22080
22081             oTarget.cursorIsOver = loc.contains( pt );
22082
22083             // DragDrop is using this as a sanity check for the initial mousedown
22084             // in this case we are done.  In POINT mode, if the drag obj has no
22085             // contraints, we are also done. Otherwise we need to evaluate the
22086             // location of the target as related to the actual location of the
22087             // dragged element.
22088             var dc = this.dragCurrent;
22089             if (!dc || !dc.getTargetCoord ||
22090                     (!intersect && !dc.constrainX && !dc.constrainY)) {
22091                 return oTarget.cursorIsOver;
22092             }
22093
22094             oTarget.overlap = null;
22095
22096             // Get the current location of the drag element, this is the
22097             // location of the mouse event less the delta that represents
22098             // where the original mousedown happened on the element.  We
22099             // need to consider constraints and ticks as well.
22100             var pos = dc.getTargetCoord(pt.x, pt.y);
22101
22102             var el = dc.getDragEl();
22103             var curRegion = new Roo.lib.Region( pos.y,
22104                                                    pos.x + el.offsetWidth,
22105                                                    pos.y + el.offsetHeight,
22106                                                    pos.x );
22107
22108             var overlap = curRegion.intersect(loc);
22109
22110             if (overlap) {
22111                 oTarget.overlap = overlap;
22112                 return (intersect) ? true : oTarget.cursorIsOver;
22113             } else {
22114                 return false;
22115             }
22116         },
22117
22118         /**
22119          * unload event handler
22120          * @method _onUnload
22121          * @private
22122          * @static
22123          */
22124         _onUnload: function(e, me) {
22125             Roo.dd.DragDropMgr.unregAll();
22126         },
22127
22128         /**
22129          * Cleans up the drag and drop events and objects.
22130          * @method unregAll
22131          * @private
22132          * @static
22133          */
22134         unregAll: function() {
22135
22136             if (this.dragCurrent) {
22137                 this.stopDrag();
22138                 this.dragCurrent = null;
22139             }
22140
22141             this._execOnAll("unreg", []);
22142
22143             for (i in this.elementCache) {
22144                 delete this.elementCache[i];
22145             }
22146
22147             this.elementCache = {};
22148             this.ids = {};
22149         },
22150
22151         /**
22152          * A cache of DOM elements
22153          * @property elementCache
22154          * @private
22155          * @static
22156          */
22157         elementCache: {},
22158
22159         /**
22160          * Get the wrapper for the DOM element specified
22161          * @method getElWrapper
22162          * @param {String} id the id of the element to get
22163          * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
22164          * @private
22165          * @deprecated This wrapper isn't that useful
22166          * @static
22167          */
22168         getElWrapper: function(id) {
22169             var oWrapper = this.elementCache[id];
22170             if (!oWrapper || !oWrapper.el) {
22171                 oWrapper = this.elementCache[id] =
22172                     new this.ElementWrapper(Roo.getDom(id));
22173             }
22174             return oWrapper;
22175         },
22176
22177         /**
22178          * Returns the actual DOM element
22179          * @method getElement
22180          * @param {String} id the id of the elment to get
22181          * @return {Object} The element
22182          * @deprecated use Roo.getDom instead
22183          * @static
22184          */
22185         getElement: function(id) {
22186             return Roo.getDom(id);
22187         },
22188
22189         /**
22190          * Returns the style property for the DOM element (i.e.,
22191          * document.getElById(id).style)
22192          * @method getCss
22193          * @param {String} id the id of the elment to get
22194          * @return {Object} The style property of the element
22195          * @deprecated use Roo.getDom instead
22196          * @static
22197          */
22198         getCss: function(id) {
22199             var el = Roo.getDom(id);
22200             return (el) ? el.style : null;
22201         },
22202
22203         /**
22204          * Inner class for cached elements
22205          * @class DragDropMgr.ElementWrapper
22206          * @for DragDropMgr
22207          * @private
22208          * @deprecated
22209          */
22210         ElementWrapper: function(el) {
22211                 /**
22212                  * The element
22213                  * @property el
22214                  */
22215                 this.el = el || null;
22216                 /**
22217                  * The element id
22218                  * @property id
22219                  */
22220                 this.id = this.el && el.id;
22221                 /**
22222                  * A reference to the style property
22223                  * @property css
22224                  */
22225                 this.css = this.el && el.style;
22226             },
22227
22228         /**
22229          * Returns the X position of an html element
22230          * @method getPosX
22231          * @param el the element for which to get the position
22232          * @return {int} the X coordinate
22233          * @for DragDropMgr
22234          * @deprecated use Roo.lib.Dom.getX instead
22235          * @static
22236          */
22237         getPosX: function(el) {
22238             return Roo.lib.Dom.getX(el);
22239         },
22240
22241         /**
22242          * Returns the Y position of an html element
22243          * @method getPosY
22244          * @param el the element for which to get the position
22245          * @return {int} the Y coordinate
22246          * @deprecated use Roo.lib.Dom.getY instead
22247          * @static
22248          */
22249         getPosY: function(el) {
22250             return Roo.lib.Dom.getY(el);
22251         },
22252
22253         /**
22254          * Swap two nodes.  In IE, we use the native method, for others we
22255          * emulate the IE behavior
22256          * @method swapNode
22257          * @param n1 the first node to swap
22258          * @param n2 the other node to swap
22259          * @static
22260          */
22261         swapNode: function(n1, n2) {
22262             if (n1.swapNode) {
22263                 n1.swapNode(n2);
22264             } else {
22265                 var p = n2.parentNode;
22266                 var s = n2.nextSibling;
22267
22268                 if (s == n1) {
22269                     p.insertBefore(n1, n2);
22270                 } else if (n2 == n1.nextSibling) {
22271                     p.insertBefore(n2, n1);
22272                 } else {
22273                     n1.parentNode.replaceChild(n2, n1);
22274                     p.insertBefore(n1, s);
22275                 }
22276             }
22277         },
22278
22279         /**
22280          * Returns the current scroll position
22281          * @method getScroll
22282          * @private
22283          * @static
22284          */
22285         getScroll: function () {
22286             var t, l, dde=document.documentElement, db=document.body;
22287             if (dde && (dde.scrollTop || dde.scrollLeft)) {
22288                 t = dde.scrollTop;
22289                 l = dde.scrollLeft;
22290             } else if (db) {
22291                 t = db.scrollTop;
22292                 l = db.scrollLeft;
22293             } else {
22294
22295             }
22296             return { top: t, left: l };
22297         },
22298
22299         /**
22300          * Returns the specified element style property
22301          * @method getStyle
22302          * @param {HTMLElement} el          the element
22303          * @param {string}      styleProp   the style property
22304          * @return {string} The value of the style property
22305          * @deprecated use Roo.lib.Dom.getStyle
22306          * @static
22307          */
22308         getStyle: function(el, styleProp) {
22309             return Roo.fly(el).getStyle(styleProp);
22310         },
22311
22312         /**
22313          * Gets the scrollTop
22314          * @method getScrollTop
22315          * @return {int} the document's scrollTop
22316          * @static
22317          */
22318         getScrollTop: function () { return this.getScroll().top; },
22319
22320         /**
22321          * Gets the scrollLeft
22322          * @method getScrollLeft
22323          * @return {int} the document's scrollTop
22324          * @static
22325          */
22326         getScrollLeft: function () { return this.getScroll().left; },
22327
22328         /**
22329          * Sets the x/y position of an element to the location of the
22330          * target element.
22331          * @method moveToEl
22332          * @param {HTMLElement} moveEl      The element to move
22333          * @param {HTMLElement} targetEl    The position reference element
22334          * @static
22335          */
22336         moveToEl: function (moveEl, targetEl) {
22337             var aCoord = Roo.lib.Dom.getXY(targetEl);
22338             Roo.lib.Dom.setXY(moveEl, aCoord);
22339         },
22340
22341         /**
22342          * Numeric array sort function
22343          * @method numericSort
22344          * @static
22345          */
22346         numericSort: function(a, b) { return (a - b); },
22347
22348         /**
22349          * Internal counter
22350          * @property _timeoutCount
22351          * @private
22352          * @static
22353          */
22354         _timeoutCount: 0,
22355
22356         /**
22357          * Trying to make the load order less important.  Without this we get
22358          * an error if this file is loaded before the Event Utility.
22359          * @method _addListeners
22360          * @private
22361          * @static
22362          */
22363         _addListeners: function() {
22364             var DDM = Roo.dd.DDM;
22365             if ( Roo.lib.Event && document ) {
22366                 DDM._onLoad();
22367             } else {
22368                 if (DDM._timeoutCount > 2000) {
22369                 } else {
22370                     setTimeout(DDM._addListeners, 10);
22371                     if (document && document.body) {
22372                         DDM._timeoutCount += 1;
22373                     }
22374                 }
22375             }
22376         },
22377
22378         /**
22379          * Recursively searches the immediate parent and all child nodes for
22380          * the handle element in order to determine wheter or not it was
22381          * clicked.
22382          * @method handleWasClicked
22383          * @param node the html element to inspect
22384          * @static
22385          */
22386         handleWasClicked: function(node, id) {
22387             if (this.isHandle(id, node.id)) {
22388                 return true;
22389             } else {
22390                 // check to see if this is a text node child of the one we want
22391                 var p = node.parentNode;
22392
22393                 while (p) {
22394                     if (this.isHandle(id, p.id)) {
22395                         return true;
22396                     } else {
22397                         p = p.parentNode;
22398                     }
22399                 }
22400             }
22401
22402             return false;
22403         }
22404
22405     };
22406
22407 }();
22408
22409 // shorter alias, save a few bytes
22410 Roo.dd.DDM = Roo.dd.DragDropMgr;
22411 Roo.dd.DDM._addListeners();
22412
22413 }/*
22414  * Based on:
22415  * Ext JS Library 1.1.1
22416  * Copyright(c) 2006-2007, Ext JS, LLC.
22417  *
22418  * Originally Released Under LGPL - original licence link has changed is not relivant.
22419  *
22420  * Fork - LGPL
22421  * <script type="text/javascript">
22422  */
22423
22424 /**
22425  * @class Roo.dd.DD
22426  * A DragDrop implementation where the linked element follows the
22427  * mouse cursor during a drag.
22428  * @extends Roo.dd.DragDrop
22429  * @constructor
22430  * @param {String} id the id of the linked element
22431  * @param {String} sGroup the group of related DragDrop items
22432  * @param {object} config an object containing configurable attributes
22433  *                Valid properties for DD:
22434  *                    scroll
22435  */
22436 Roo.dd.DD = function(id, sGroup, config) {
22437     if (id) {
22438         this.init(id, sGroup, config);
22439     }
22440 };
22441
22442 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
22443
22444     /**
22445      * When set to true, the utility automatically tries to scroll the browser
22446      * window wehn a drag and drop element is dragged near the viewport boundary.
22447      * Defaults to true.
22448      * @property scroll
22449      * @type boolean
22450      */
22451     scroll: true,
22452
22453     /**
22454      * Sets the pointer offset to the distance between the linked element's top
22455      * left corner and the location the element was clicked
22456      * @method autoOffset
22457      * @param {int} iPageX the X coordinate of the click
22458      * @param {int} iPageY the Y coordinate of the click
22459      */
22460     autoOffset: function(iPageX, iPageY) {
22461         var x = iPageX - this.startPageX;
22462         var y = iPageY - this.startPageY;
22463         this.setDelta(x, y);
22464     },
22465
22466     /**
22467      * Sets the pointer offset.  You can call this directly to force the
22468      * offset to be in a particular location (e.g., pass in 0,0 to set it
22469      * to the center of the object)
22470      * @method setDelta
22471      * @param {int} iDeltaX the distance from the left
22472      * @param {int} iDeltaY the distance from the top
22473      */
22474     setDelta: function(iDeltaX, iDeltaY) {
22475         this.deltaX = iDeltaX;
22476         this.deltaY = iDeltaY;
22477     },
22478
22479     /**
22480      * Sets the drag element to the location of the mousedown or click event,
22481      * maintaining the cursor location relative to the location on the element
22482      * that was clicked.  Override this if you want to place the element in a
22483      * location other than where the cursor is.
22484      * @method setDragElPos
22485      * @param {int} iPageX the X coordinate of the mousedown or drag event
22486      * @param {int} iPageY the Y coordinate of the mousedown or drag event
22487      */
22488     setDragElPos: function(iPageX, iPageY) {
22489         // the first time we do this, we are going to check to make sure
22490         // the element has css positioning
22491
22492         var el = this.getDragEl();
22493         this.alignElWithMouse(el, iPageX, iPageY);
22494     },
22495
22496     /**
22497      * Sets the element to the location of the mousedown or click event,
22498      * maintaining the cursor location relative to the location on the element
22499      * that was clicked.  Override this if you want to place the element in a
22500      * location other than where the cursor is.
22501      * @method alignElWithMouse
22502      * @param {HTMLElement} el the element to move
22503      * @param {int} iPageX the X coordinate of the mousedown or drag event
22504      * @param {int} iPageY the Y coordinate of the mousedown or drag event
22505      */
22506     alignElWithMouse: function(el, iPageX, iPageY) {
22507         var oCoord = this.getTargetCoord(iPageX, iPageY);
22508         var fly = el.dom ? el : Roo.fly(el);
22509         if (!this.deltaSetXY) {
22510             var aCoord = [oCoord.x, oCoord.y];
22511             fly.setXY(aCoord);
22512             var newLeft = fly.getLeft(true);
22513             var newTop  = fly.getTop(true);
22514             this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
22515         } else {
22516             fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
22517         }
22518
22519         this.cachePosition(oCoord.x, oCoord.y);
22520         this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
22521         return oCoord;
22522     },
22523
22524     /**
22525      * Saves the most recent position so that we can reset the constraints and
22526      * tick marks on-demand.  We need to know this so that we can calculate the
22527      * number of pixels the element is offset from its original position.
22528      * @method cachePosition
22529      * @param iPageX the current x position (optional, this just makes it so we
22530      * don't have to look it up again)
22531      * @param iPageY the current y position (optional, this just makes it so we
22532      * don't have to look it up again)
22533      */
22534     cachePosition: function(iPageX, iPageY) {
22535         if (iPageX) {
22536             this.lastPageX = iPageX;
22537             this.lastPageY = iPageY;
22538         } else {
22539             var aCoord = Roo.lib.Dom.getXY(this.getEl());
22540             this.lastPageX = aCoord[0];
22541             this.lastPageY = aCoord[1];
22542         }
22543     },
22544
22545     /**
22546      * Auto-scroll the window if the dragged object has been moved beyond the
22547      * visible window boundary.
22548      * @method autoScroll
22549      * @param {int} x the drag element's x position
22550      * @param {int} y the drag element's y position
22551      * @param {int} h the height of the drag element
22552      * @param {int} w the width of the drag element
22553      * @private
22554      */
22555     autoScroll: function(x, y, h, w) {
22556
22557         if (this.scroll) {
22558             // The client height
22559             var clientH = Roo.lib.Dom.getViewWidth();
22560
22561             // The client width
22562             var clientW = Roo.lib.Dom.getViewHeight();
22563
22564             // The amt scrolled down
22565             var st = this.DDM.getScrollTop();
22566
22567             // The amt scrolled right
22568             var sl = this.DDM.getScrollLeft();
22569
22570             // Location of the bottom of the element
22571             var bot = h + y;
22572
22573             // Location of the right of the element
22574             var right = w + x;
22575
22576             // The distance from the cursor to the bottom of the visible area,
22577             // adjusted so that we don't scroll if the cursor is beyond the
22578             // element drag constraints
22579             var toBot = (clientH + st - y - this.deltaY);
22580
22581             // The distance from the cursor to the right of the visible area
22582             var toRight = (clientW + sl - x - this.deltaX);
22583
22584
22585             // How close to the edge the cursor must be before we scroll
22586             // var thresh = (document.all) ? 100 : 40;
22587             var thresh = 40;
22588
22589             // How many pixels to scroll per autoscroll op.  This helps to reduce
22590             // clunky scrolling. IE is more sensitive about this ... it needs this
22591             // value to be higher.
22592             var scrAmt = (document.all) ? 80 : 30;
22593
22594             // Scroll down if we are near the bottom of the visible page and the
22595             // obj extends below the crease
22596             if ( bot > clientH && toBot < thresh ) {
22597                 window.scrollTo(sl, st + scrAmt);
22598             }
22599
22600             // Scroll up if the window is scrolled down and the top of the object
22601             // goes above the top border
22602             if ( y < st && st > 0 && y - st < thresh ) {
22603                 window.scrollTo(sl, st - scrAmt);
22604             }
22605
22606             // Scroll right if the obj is beyond the right border and the cursor is
22607             // near the border.
22608             if ( right > clientW && toRight < thresh ) {
22609                 window.scrollTo(sl + scrAmt, st);
22610             }
22611
22612             // Scroll left if the window has been scrolled to the right and the obj
22613             // extends past the left border
22614             if ( x < sl && sl > 0 && x - sl < thresh ) {
22615                 window.scrollTo(sl - scrAmt, st);
22616             }
22617         }
22618     },
22619
22620     /**
22621      * Finds the location the element should be placed if we want to move
22622      * it to where the mouse location less the click offset would place us.
22623      * @method getTargetCoord
22624      * @param {int} iPageX the X coordinate of the click
22625      * @param {int} iPageY the Y coordinate of the click
22626      * @return an object that contains the coordinates (Object.x and Object.y)
22627      * @private
22628      */
22629     getTargetCoord: function(iPageX, iPageY) {
22630
22631
22632         var x = iPageX - this.deltaX;
22633         var y = iPageY - this.deltaY;
22634
22635         if (this.constrainX) {
22636             if (x < this.minX) { x = this.minX; }
22637             if (x > this.maxX) { x = this.maxX; }
22638         }
22639
22640         if (this.constrainY) {
22641             if (y < this.minY) { y = this.minY; }
22642             if (y > this.maxY) { y = this.maxY; }
22643         }
22644
22645         x = this.getTick(x, this.xTicks);
22646         y = this.getTick(y, this.yTicks);
22647
22648
22649         return {x:x, y:y};
22650     },
22651
22652     /*
22653      * Sets up config options specific to this class. Overrides
22654      * Roo.dd.DragDrop, but all versions of this method through the
22655      * inheritance chain are called
22656      */
22657     applyConfig: function() {
22658         Roo.dd.DD.superclass.applyConfig.call(this);
22659         this.scroll = (this.config.scroll !== false);
22660     },
22661
22662     /*
22663      * Event that fires prior to the onMouseDown event.  Overrides
22664      * Roo.dd.DragDrop.
22665      */
22666     b4MouseDown: function(e) {
22667         // this.resetConstraints();
22668         this.autoOffset(e.getPageX(),
22669                             e.getPageY());
22670     },
22671
22672     /*
22673      * Event that fires prior to the onDrag event.  Overrides
22674      * Roo.dd.DragDrop.
22675      */
22676     b4Drag: function(e) {
22677         this.setDragElPos(e.getPageX(),
22678                             e.getPageY());
22679     },
22680
22681     toString: function() {
22682         return ("DD " + this.id);
22683     }
22684
22685     //////////////////////////////////////////////////////////////////////////
22686     // Debugging ygDragDrop events that can be overridden
22687     //////////////////////////////////////////////////////////////////////////
22688     /*
22689     startDrag: function(x, y) {
22690     },
22691
22692     onDrag: function(e) {
22693     },
22694
22695     onDragEnter: function(e, id) {
22696     },
22697
22698     onDragOver: function(e, id) {
22699     },
22700
22701     onDragOut: function(e, id) {
22702     },
22703
22704     onDragDrop: function(e, id) {
22705     },
22706
22707     endDrag: function(e) {
22708     }
22709
22710     */
22711
22712 });/*
22713  * Based on:
22714  * Ext JS Library 1.1.1
22715  * Copyright(c) 2006-2007, Ext JS, LLC.
22716  *
22717  * Originally Released Under LGPL - original licence link has changed is not relivant.
22718  *
22719  * Fork - LGPL
22720  * <script type="text/javascript">
22721  */
22722
22723 /**
22724  * @class Roo.dd.DDProxy
22725  * A DragDrop implementation that inserts an empty, bordered div into
22726  * the document that follows the cursor during drag operations.  At the time of
22727  * the click, the frame div is resized to the dimensions of the linked html
22728  * element, and moved to the exact location of the linked element.
22729  *
22730  * References to the "frame" element refer to the single proxy element that
22731  * was created to be dragged in place of all DDProxy elements on the
22732  * page.
22733  *
22734  * @extends Roo.dd.DD
22735  * @constructor
22736  * @param {String} id the id of the linked html element
22737  * @param {String} sGroup the group of related DragDrop objects
22738  * @param {object} config an object containing configurable attributes
22739  *                Valid properties for DDProxy in addition to those in DragDrop:
22740  *                   resizeFrame, centerFrame, dragElId
22741  */
22742 Roo.dd.DDProxy = function(id, sGroup, config) {
22743     if (id) {
22744         this.init(id, sGroup, config);
22745         this.initFrame();
22746     }
22747 };
22748
22749 /**
22750  * The default drag frame div id
22751  * @property Roo.dd.DDProxy.dragElId
22752  * @type String
22753  * @static
22754  */
22755 Roo.dd.DDProxy.dragElId = "ygddfdiv";
22756
22757 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
22758
22759     /**
22760      * By default we resize the drag frame to be the same size as the element
22761      * we want to drag (this is to get the frame effect).  We can turn it off
22762      * if we want a different behavior.
22763      * @property resizeFrame
22764      * @type boolean
22765      */
22766     resizeFrame: true,
22767
22768     /**
22769      * By default the frame is positioned exactly where the drag element is, so
22770      * we use the cursor offset provided by Roo.dd.DD.  Another option that works only if
22771      * you do not have constraints on the obj is to have the drag frame centered
22772      * around the cursor.  Set centerFrame to true for this effect.
22773      * @property centerFrame
22774      * @type boolean
22775      */
22776     centerFrame: false,
22777
22778     /**
22779      * Creates the proxy element if it does not yet exist
22780      * @method createFrame
22781      */
22782     createFrame: function() {
22783         var self = this;
22784         var body = document.body;
22785
22786         if (!body || !body.firstChild) {
22787             setTimeout( function() { self.createFrame(); }, 50 );
22788             return;
22789         }
22790
22791         var div = this.getDragEl();
22792
22793         if (!div) {
22794             div    = document.createElement("div");
22795             div.id = this.dragElId;
22796             var s  = div.style;
22797
22798             s.position   = "absolute";
22799             s.visibility = "hidden";
22800             s.cursor     = "move";
22801             s.border     = "2px solid #aaa";
22802             s.zIndex     = 999;
22803
22804             // appendChild can blow up IE if invoked prior to the window load event
22805             // while rendering a table.  It is possible there are other scenarios
22806             // that would cause this to happen as well.
22807             body.insertBefore(div, body.firstChild);
22808         }
22809     },
22810
22811     /**
22812      * Initialization for the drag frame element.  Must be called in the
22813      * constructor of all subclasses
22814      * @method initFrame
22815      */
22816     initFrame: function() {
22817         this.createFrame();
22818     },
22819
22820     applyConfig: function() {
22821         Roo.dd.DDProxy.superclass.applyConfig.call(this);
22822
22823         this.resizeFrame = (this.config.resizeFrame !== false);
22824         this.centerFrame = (this.config.centerFrame);
22825         this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
22826     },
22827
22828     /**
22829      * Resizes the drag frame to the dimensions of the clicked object, positions
22830      * it over the object, and finally displays it
22831      * @method showFrame
22832      * @param {int} iPageX X click position
22833      * @param {int} iPageY Y click position
22834      * @private
22835      */
22836     showFrame: function(iPageX, iPageY) {
22837         var el = this.getEl();
22838         var dragEl = this.getDragEl();
22839         var s = dragEl.style;
22840
22841         this._resizeProxy();
22842
22843         if (this.centerFrame) {
22844             this.setDelta( Math.round(parseInt(s.width,  10)/2),
22845                            Math.round(parseInt(s.height, 10)/2) );
22846         }
22847
22848         this.setDragElPos(iPageX, iPageY);
22849
22850         Roo.fly(dragEl).show();
22851     },
22852
22853     /**
22854      * The proxy is automatically resized to the dimensions of the linked
22855      * element when a drag is initiated, unless resizeFrame is set to false
22856      * @method _resizeProxy
22857      * @private
22858      */
22859     _resizeProxy: function() {
22860         if (this.resizeFrame) {
22861             var el = this.getEl();
22862             Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
22863         }
22864     },
22865
22866     // overrides Roo.dd.DragDrop
22867     b4MouseDown: function(e) {
22868         var x = e.getPageX();
22869         var y = e.getPageY();
22870         this.autoOffset(x, y);
22871         this.setDragElPos(x, y);
22872     },
22873
22874     // overrides Roo.dd.DragDrop
22875     b4StartDrag: function(x, y) {
22876         // show the drag frame
22877         this.showFrame(x, y);
22878     },
22879
22880     // overrides Roo.dd.DragDrop
22881     b4EndDrag: function(e) {
22882         Roo.fly(this.getDragEl()).hide();
22883     },
22884
22885     // overrides Roo.dd.DragDrop
22886     // By default we try to move the element to the last location of the frame.
22887     // This is so that the default behavior mirrors that of Roo.dd.DD.
22888     endDrag: function(e) {
22889
22890         var lel = this.getEl();
22891         var del = this.getDragEl();
22892
22893         // Show the drag frame briefly so we can get its position
22894         del.style.visibility = "";
22895
22896         this.beforeMove();
22897         // Hide the linked element before the move to get around a Safari
22898         // rendering bug.
22899         lel.style.visibility = "hidden";
22900         Roo.dd.DDM.moveToEl(lel, del);
22901         del.style.visibility = "hidden";
22902         lel.style.visibility = "";
22903
22904         this.afterDrag();
22905     },
22906
22907     beforeMove : function(){
22908
22909     },
22910
22911     afterDrag : function(){
22912
22913     },
22914
22915     toString: function() {
22916         return ("DDProxy " + this.id);
22917     }
22918
22919 });
22920 /*
22921  * Based on:
22922  * Ext JS Library 1.1.1
22923  * Copyright(c) 2006-2007, Ext JS, LLC.
22924  *
22925  * Originally Released Under LGPL - original licence link has changed is not relivant.
22926  *
22927  * Fork - LGPL
22928  * <script type="text/javascript">
22929  */
22930
22931  /**
22932  * @class Roo.dd.DDTarget
22933  * A DragDrop implementation that does not move, but can be a drop
22934  * target.  You would get the same result by simply omitting implementation
22935  * for the event callbacks, but this way we reduce the processing cost of the
22936  * event listener and the callbacks.
22937  * @extends Roo.dd.DragDrop
22938  * @constructor
22939  * @param {String} id the id of the element that is a drop target
22940  * @param {String} sGroup the group of related DragDrop objects
22941  * @param {object} config an object containing configurable attributes
22942  *                 Valid properties for DDTarget in addition to those in
22943  *                 DragDrop:
22944  *                    none
22945  */
22946 Roo.dd.DDTarget = function(id, sGroup, config) {
22947     if (id) {
22948         this.initTarget(id, sGroup, config);
22949     }
22950     if (config && (config.listeners || config.events)) { 
22951         Roo.dd.DragDrop.superclass.constructor.call(this,  { 
22952             listeners : config.listeners || {}, 
22953             events : config.events || {} 
22954         });    
22955     }
22956 };
22957
22958 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
22959 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
22960     toString: function() {
22961         return ("DDTarget " + this.id);
22962     }
22963 });
22964 /*
22965  * Based on:
22966  * Ext JS Library 1.1.1
22967  * Copyright(c) 2006-2007, Ext JS, LLC.
22968  *
22969  * Originally Released Under LGPL - original licence link has changed is not relivant.
22970  *
22971  * Fork - LGPL
22972  * <script type="text/javascript">
22973  */
22974  
22975
22976 /**
22977  * @class Roo.dd.ScrollManager
22978  * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
22979  * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
22980  * @static
22981  */
22982 Roo.dd.ScrollManager = function(){
22983     var ddm = Roo.dd.DragDropMgr;
22984     var els = {};
22985     var dragEl = null;
22986     var proc = {};
22987     
22988     
22989     
22990     var onStop = function(e){
22991         dragEl = null;
22992         clearProc();
22993     };
22994     
22995     var triggerRefresh = function(){
22996         if(ddm.dragCurrent){
22997              ddm.refreshCache(ddm.dragCurrent.groups);
22998         }
22999     };
23000     
23001     var doScroll = function(){
23002         if(ddm.dragCurrent){
23003             var dds = Roo.dd.ScrollManager;
23004             if(!dds.animate){
23005                 if(proc.el.scroll(proc.dir, dds.increment)){
23006                     triggerRefresh();
23007                 }
23008             }else{
23009                 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
23010             }
23011         }
23012     };
23013     
23014     var clearProc = function(){
23015         if(proc.id){
23016             clearInterval(proc.id);
23017         }
23018         proc.id = 0;
23019         proc.el = null;
23020         proc.dir = "";
23021     };
23022     
23023     var startProc = function(el, dir){
23024          Roo.log('scroll startproc');
23025         clearProc();
23026         proc.el = el;
23027         proc.dir = dir;
23028         proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
23029     };
23030     
23031     var onFire = function(e, isDrop){
23032        
23033         if(isDrop || !ddm.dragCurrent){ return; }
23034         var dds = Roo.dd.ScrollManager;
23035         if(!dragEl || dragEl != ddm.dragCurrent){
23036             dragEl = ddm.dragCurrent;
23037             // refresh regions on drag start
23038             dds.refreshCache();
23039         }
23040         
23041         var xy = Roo.lib.Event.getXY(e);
23042         var pt = new Roo.lib.Point(xy[0], xy[1]);
23043         for(var id in els){
23044             var el = els[id], r = el._region;
23045             if(r && r.contains(pt) && el.isScrollable()){
23046                 if(r.bottom - pt.y <= dds.thresh){
23047                     if(proc.el != el){
23048                         startProc(el, "down");
23049                     }
23050                     return;
23051                 }else if(r.right - pt.x <= dds.thresh){
23052                     if(proc.el != el){
23053                         startProc(el, "left");
23054                     }
23055                     return;
23056                 }else if(pt.y - r.top <= dds.thresh){
23057                     if(proc.el != el){
23058                         startProc(el, "up");
23059                     }
23060                     return;
23061                 }else if(pt.x - r.left <= dds.thresh){
23062                     if(proc.el != el){
23063                         startProc(el, "right");
23064                     }
23065                     return;
23066                 }
23067             }
23068         }
23069         clearProc();
23070     };
23071     
23072     ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
23073     ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
23074     
23075     return {
23076         /**
23077          * Registers new overflow element(s) to auto scroll
23078          * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
23079          */
23080         register : function(el){
23081             if(el instanceof Array){
23082                 for(var i = 0, len = el.length; i < len; i++) {
23083                         this.register(el[i]);
23084                 }
23085             }else{
23086                 el = Roo.get(el);
23087                 els[el.id] = el;
23088             }
23089             Roo.dd.ScrollManager.els = els;
23090         },
23091         
23092         /**
23093          * Unregisters overflow element(s) so they are no longer scrolled
23094          * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
23095          */
23096         unregister : function(el){
23097             if(el instanceof Array){
23098                 for(var i = 0, len = el.length; i < len; i++) {
23099                         this.unregister(el[i]);
23100                 }
23101             }else{
23102                 el = Roo.get(el);
23103                 delete els[el.id];
23104             }
23105         },
23106         
23107         /**
23108          * The number of pixels from the edge of a container the pointer needs to be to 
23109          * trigger scrolling (defaults to 25)
23110          * @type Number
23111          */
23112         thresh : 25,
23113         
23114         /**
23115          * The number of pixels to scroll in each scroll increment (defaults to 50)
23116          * @type Number
23117          */
23118         increment : 100,
23119         
23120         /**
23121          * The frequency of scrolls in milliseconds (defaults to 500)
23122          * @type Number
23123          */
23124         frequency : 500,
23125         
23126         /**
23127          * True to animate the scroll (defaults to true)
23128          * @type Boolean
23129          */
23130         animate: true,
23131         
23132         /**
23133          * The animation duration in seconds - 
23134          * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
23135          * @type Number
23136          */
23137         animDuration: .4,
23138         
23139         /**
23140          * Manually trigger a cache refresh.
23141          */
23142         refreshCache : function(){
23143             for(var id in els){
23144                 if(typeof els[id] == 'object'){ // for people extending the object prototype
23145                     els[id]._region = els[id].getRegion();
23146                 }
23147             }
23148         }
23149     };
23150 }();/*
23151  * Based on:
23152  * Ext JS Library 1.1.1
23153  * Copyright(c) 2006-2007, Ext JS, LLC.
23154  *
23155  * Originally Released Under LGPL - original licence link has changed is not relivant.
23156  *
23157  * Fork - LGPL
23158  * <script type="text/javascript">
23159  */
23160  
23161
23162 /**
23163  * @class Roo.dd.Registry
23164  * Provides easy access to all drag drop components that are registered on a page.  Items can be retrieved either
23165  * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
23166  * @static
23167  */
23168 Roo.dd.Registry = function(){
23169     var elements = {}; 
23170     var handles = {}; 
23171     var autoIdSeed = 0;
23172
23173     var getId = function(el, autogen){
23174         if(typeof el == "string"){
23175             return el;
23176         }
23177         var id = el.id;
23178         if(!id && autogen !== false){
23179             id = "roodd-" + (++autoIdSeed);
23180             el.id = id;
23181         }
23182         return id;
23183     };
23184     
23185     return {
23186     /**
23187      * Register a drag drop element
23188      * @param {String|HTMLElement} element The id or DOM node to register
23189      * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
23190      * in drag drop operations.  You can populate this object with any arbitrary properties that your own code
23191      * knows how to interpret, plus there are some specific properties known to the Registry that should be
23192      * populated in the data object (if applicable):
23193      * <pre>
23194 Value      Description<br />
23195 ---------  ------------------------------------------<br />
23196 handles    Array of DOM nodes that trigger dragging<br />
23197            for the element being registered<br />
23198 isHandle   True if the element passed in triggers<br />
23199            dragging itself, else false
23200 </pre>
23201      */
23202         register : function(el, data){
23203             data = data || {};
23204             if(typeof el == "string"){
23205                 el = document.getElementById(el);
23206             }
23207             data.ddel = el;
23208             elements[getId(el)] = data;
23209             if(data.isHandle !== false){
23210                 handles[data.ddel.id] = data;
23211             }
23212             if(data.handles){
23213                 var hs = data.handles;
23214                 for(var i = 0, len = hs.length; i < len; i++){
23215                         handles[getId(hs[i])] = data;
23216                 }
23217             }
23218         },
23219
23220     /**
23221      * Unregister a drag drop element
23222      * @param {String|HTMLElement}  element The id or DOM node to unregister
23223      */
23224         unregister : function(el){
23225             var id = getId(el, false);
23226             var data = elements[id];
23227             if(data){
23228                 delete elements[id];
23229                 if(data.handles){
23230                     var hs = data.handles;
23231                     for(var i = 0, len = hs.length; i < len; i++){
23232                         delete handles[getId(hs[i], false)];
23233                     }
23234                 }
23235             }
23236         },
23237
23238     /**
23239      * Returns the handle registered for a DOM Node by id
23240      * @param {String|HTMLElement} id The DOM node or id to look up
23241      * @return {Object} handle The custom handle data
23242      */
23243         getHandle : function(id){
23244             if(typeof id != "string"){ // must be element?
23245                 id = id.id;
23246             }
23247             return handles[id];
23248         },
23249
23250     /**
23251      * Returns the handle that is registered for the DOM node that is the target of the event
23252      * @param {Event} e The event
23253      * @return {Object} handle The custom handle data
23254      */
23255         getHandleFromEvent : function(e){
23256             var t = Roo.lib.Event.getTarget(e);
23257             return t ? handles[t.id] : null;
23258         },
23259
23260     /**
23261      * Returns a custom data object that is registered for a DOM node by id
23262      * @param {String|HTMLElement} id The DOM node or id to look up
23263      * @return {Object} data The custom data
23264      */
23265         getTarget : function(id){
23266             if(typeof id != "string"){ // must be element?
23267                 id = id.id;
23268             }
23269             return elements[id];
23270         },
23271
23272     /**
23273      * Returns a custom data object that is registered for the DOM node that is the target of the event
23274      * @param {Event} e The event
23275      * @return {Object} data The custom data
23276      */
23277         getTargetFromEvent : function(e){
23278             var t = Roo.lib.Event.getTarget(e);
23279             return t ? elements[t.id] || handles[t.id] : null;
23280         }
23281     };
23282 }();/*
23283  * Based on:
23284  * Ext JS Library 1.1.1
23285  * Copyright(c) 2006-2007, Ext JS, LLC.
23286  *
23287  * Originally Released Under LGPL - original licence link has changed is not relivant.
23288  *
23289  * Fork - LGPL
23290  * <script type="text/javascript">
23291  */
23292  
23293
23294 /**
23295  * @class Roo.dd.StatusProxy
23296  * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair.  This is the
23297  * default drag proxy used by all Roo.dd components.
23298  * @constructor
23299  * @param {Object} config
23300  */
23301 Roo.dd.StatusProxy = function(config){
23302     Roo.apply(this, config);
23303     this.id = this.id || Roo.id();
23304     this.el = new Roo.Layer({
23305         dh: {
23306             id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
23307                 {tag: "div", cls: "x-dd-drop-icon"},
23308                 {tag: "div", cls: "x-dd-drag-ghost"}
23309             ]
23310         }, 
23311         shadow: !config || config.shadow !== false
23312     });
23313     this.ghost = Roo.get(this.el.dom.childNodes[1]);
23314     this.dropStatus = this.dropNotAllowed;
23315 };
23316
23317 Roo.dd.StatusProxy.prototype = {
23318     /**
23319      * @cfg {String} dropAllowed
23320      * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
23321      */
23322     dropAllowed : "x-dd-drop-ok",
23323     /**
23324      * @cfg {String} dropNotAllowed
23325      * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
23326      */
23327     dropNotAllowed : "x-dd-drop-nodrop",
23328
23329     /**
23330      * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
23331      * over the current target element.
23332      * @param {String} cssClass The css class for the new drop status indicator image
23333      */
23334     setStatus : function(cssClass){
23335         cssClass = cssClass || this.dropNotAllowed;
23336         if(this.dropStatus != cssClass){
23337             this.el.replaceClass(this.dropStatus, cssClass);
23338             this.dropStatus = cssClass;
23339         }
23340     },
23341
23342     /**
23343      * Resets the status indicator to the default dropNotAllowed value
23344      * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
23345      */
23346     reset : function(clearGhost){
23347         this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
23348         this.dropStatus = this.dropNotAllowed;
23349         if(clearGhost){
23350             this.ghost.update("");
23351         }
23352     },
23353
23354     /**
23355      * Updates the contents of the ghost element
23356      * @param {String} html The html that will replace the current innerHTML of the ghost element
23357      */
23358     update : function(html){
23359         if(typeof html == "string"){
23360             this.ghost.update(html);
23361         }else{
23362             this.ghost.update("");
23363             html.style.margin = "0";
23364             this.ghost.dom.appendChild(html);
23365         }
23366         // ensure float = none set?? cant remember why though.
23367         var el = this.ghost.dom.firstChild;
23368                 if(el){
23369                         Roo.fly(el).setStyle('float', 'none');
23370                 }
23371     },
23372     
23373     /**
23374      * Returns the underlying proxy {@link Roo.Layer}
23375      * @return {Roo.Layer} el
23376     */
23377     getEl : function(){
23378         return this.el;
23379     },
23380
23381     /**
23382      * Returns the ghost element
23383      * @return {Roo.Element} el
23384      */
23385     getGhost : function(){
23386         return this.ghost;
23387     },
23388
23389     /**
23390      * Hides the proxy
23391      * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
23392      */
23393     hide : function(clear){
23394         this.el.hide();
23395         if(clear){
23396             this.reset(true);
23397         }
23398     },
23399
23400     /**
23401      * Stops the repair animation if it's currently running
23402      */
23403     stop : function(){
23404         if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
23405             this.anim.stop();
23406         }
23407     },
23408
23409     /**
23410      * Displays this proxy
23411      */
23412     show : function(){
23413         this.el.show();
23414     },
23415
23416     /**
23417      * Force the Layer to sync its shadow and shim positions to the element
23418      */
23419     sync : function(){
23420         this.el.sync();
23421     },
23422
23423     /**
23424      * Causes the proxy to return to its position of origin via an animation.  Should be called after an
23425      * invalid drop operation by the item being dragged.
23426      * @param {Array} xy The XY position of the element ([x, y])
23427      * @param {Function} callback The function to call after the repair is complete
23428      * @param {Object} scope The scope in which to execute the callback
23429      */
23430     repair : function(xy, callback, scope){
23431         this.callback = callback;
23432         this.scope = scope;
23433         if(xy && this.animRepair !== false){
23434             this.el.addClass("x-dd-drag-repair");
23435             this.el.hideUnders(true);
23436             this.anim = this.el.shift({
23437                 duration: this.repairDuration || .5,
23438                 easing: 'easeOut',
23439                 xy: xy,
23440                 stopFx: true,
23441                 callback: this.afterRepair,
23442                 scope: this
23443             });
23444         }else{
23445             this.afterRepair();
23446         }
23447     },
23448
23449     // private
23450     afterRepair : function(){
23451         this.hide(true);
23452         if(typeof this.callback == "function"){
23453             this.callback.call(this.scope || this);
23454         }
23455         this.callback = null;
23456         this.scope = null;
23457     }
23458 };/*
23459  * Based on:
23460  * Ext JS Library 1.1.1
23461  * Copyright(c) 2006-2007, Ext JS, LLC.
23462  *
23463  * Originally Released Under LGPL - original licence link has changed is not relivant.
23464  *
23465  * Fork - LGPL
23466  * <script type="text/javascript">
23467  */
23468
23469 /**
23470  * @class Roo.dd.DragSource
23471  * @extends Roo.dd.DDProxy
23472  * A simple class that provides the basic implementation needed to make any element draggable.
23473  * @constructor
23474  * @param {String/HTMLElement/Element} el The container element
23475  * @param {Object} config
23476  */
23477 Roo.dd.DragSource = function(el, config){
23478     this.el = Roo.get(el);
23479     this.dragData = {};
23480     
23481     Roo.apply(this, config);
23482     
23483     if(!this.proxy){
23484         this.proxy = new Roo.dd.StatusProxy();
23485     }
23486
23487     Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
23488           {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
23489     
23490     this.dragging = false;
23491 };
23492
23493 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
23494     /**
23495      * @cfg {String} dropAllowed
23496      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
23497      */
23498     dropAllowed : "x-dd-drop-ok",
23499     /**
23500      * @cfg {String} dropNotAllowed
23501      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
23502      */
23503     dropNotAllowed : "x-dd-drop-nodrop",
23504
23505     /**
23506      * Returns the data object associated with this drag source
23507      * @return {Object} data An object containing arbitrary data
23508      */
23509     getDragData : function(e){
23510         return this.dragData;
23511     },
23512
23513     // private
23514     onDragEnter : function(e, id){
23515         var target = Roo.dd.DragDropMgr.getDDById(id);
23516         this.cachedTarget = target;
23517         if(this.beforeDragEnter(target, e, id) !== false){
23518             if(target.isNotifyTarget){
23519                 var status = target.notifyEnter(this, e, this.dragData);
23520                 this.proxy.setStatus(status);
23521             }else{
23522                 this.proxy.setStatus(this.dropAllowed);
23523             }
23524             
23525             if(this.afterDragEnter){
23526                 /**
23527                  * An empty function by default, but provided so that you can perform a custom action
23528                  * when the dragged item enters the drop target by providing an implementation.
23529                  * @param {Roo.dd.DragDrop} target The drop target
23530                  * @param {Event} e The event object
23531                  * @param {String} id The id of the dragged element
23532                  * @method afterDragEnter
23533                  */
23534                 this.afterDragEnter(target, e, id);
23535             }
23536         }
23537     },
23538
23539     /**
23540      * An empty function by default, but provided so that you can perform a custom action
23541      * before the dragged item enters the drop target and optionally cancel the onDragEnter.
23542      * @param {Roo.dd.DragDrop} target The drop target
23543      * @param {Event} e The event object
23544      * @param {String} id The id of the dragged element
23545      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23546      */
23547     beforeDragEnter : function(target, e, id){
23548         return true;
23549     },
23550
23551     // private
23552     alignElWithMouse: function() {
23553         Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
23554         this.proxy.sync();
23555     },
23556
23557     // private
23558     onDragOver : function(e, id){
23559         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23560         if(this.beforeDragOver(target, e, id) !== false){
23561             if(target.isNotifyTarget){
23562                 var status = target.notifyOver(this, e, this.dragData);
23563                 this.proxy.setStatus(status);
23564             }
23565
23566             if(this.afterDragOver){
23567                 /**
23568                  * An empty function by default, but provided so that you can perform a custom action
23569                  * while the dragged item is over the drop target by providing an implementation.
23570                  * @param {Roo.dd.DragDrop} target The drop target
23571                  * @param {Event} e The event object
23572                  * @param {String} id The id of the dragged element
23573                  * @method afterDragOver
23574                  */
23575                 this.afterDragOver(target, e, id);
23576             }
23577         }
23578     },
23579
23580     /**
23581      * An empty function by default, but provided so that you can perform a custom action
23582      * while the dragged item is over the drop target and optionally cancel the onDragOver.
23583      * @param {Roo.dd.DragDrop} target The drop target
23584      * @param {Event} e The event object
23585      * @param {String} id The id of the dragged element
23586      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23587      */
23588     beforeDragOver : function(target, e, id){
23589         return true;
23590     },
23591
23592     // private
23593     onDragOut : function(e, id){
23594         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23595         if(this.beforeDragOut(target, e, id) !== false){
23596             if(target.isNotifyTarget){
23597                 target.notifyOut(this, e, this.dragData);
23598             }
23599             this.proxy.reset();
23600             if(this.afterDragOut){
23601                 /**
23602                  * An empty function by default, but provided so that you can perform a custom action
23603                  * after the dragged item is dragged out of the target without dropping.
23604                  * @param {Roo.dd.DragDrop} target The drop target
23605                  * @param {Event} e The event object
23606                  * @param {String} id The id of the dragged element
23607                  * @method afterDragOut
23608                  */
23609                 this.afterDragOut(target, e, id);
23610             }
23611         }
23612         this.cachedTarget = null;
23613     },
23614
23615     /**
23616      * An empty function by default, but provided so that you can perform a custom action before the dragged
23617      * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
23618      * @param {Roo.dd.DragDrop} target The drop target
23619      * @param {Event} e The event object
23620      * @param {String} id The id of the dragged element
23621      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23622      */
23623     beforeDragOut : function(target, e, id){
23624         return true;
23625     },
23626     
23627     // private
23628     onDragDrop : function(e, id){
23629         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23630         if(this.beforeDragDrop(target, e, id) !== false){
23631             if(target.isNotifyTarget){
23632                 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
23633                     this.onValidDrop(target, e, id);
23634                 }else{
23635                     this.onInvalidDrop(target, e, id);
23636                 }
23637             }else{
23638                 this.onValidDrop(target, e, id);
23639             }
23640             
23641             if(this.afterDragDrop){
23642                 /**
23643                  * An empty function by default, but provided so that you can perform a custom action
23644                  * after a valid drag drop has occurred by providing an implementation.
23645                  * @param {Roo.dd.DragDrop} target The drop target
23646                  * @param {Event} e The event object
23647                  * @param {String} id The id of the dropped element
23648                  * @method afterDragDrop
23649                  */
23650                 this.afterDragDrop(target, e, id);
23651             }
23652         }
23653         delete this.cachedTarget;
23654     },
23655
23656     /**
23657      * An empty function by default, but provided so that you can perform a custom action before the dragged
23658      * item is dropped onto the target and optionally cancel the onDragDrop.
23659      * @param {Roo.dd.DragDrop} target The drop target
23660      * @param {Event} e The event object
23661      * @param {String} id The id of the dragged element
23662      * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
23663      */
23664     beforeDragDrop : function(target, e, id){
23665         return true;
23666     },
23667
23668     // private
23669     onValidDrop : function(target, e, id){
23670         this.hideProxy();
23671         if(this.afterValidDrop){
23672             /**
23673              * An empty function by default, but provided so that you can perform a custom action
23674              * after a valid drop has occurred by providing an implementation.
23675              * @param {Object} target The target DD 
23676              * @param {Event} e The event object
23677              * @param {String} id The id of the dropped element
23678              * @method afterInvalidDrop
23679              */
23680             this.afterValidDrop(target, e, id);
23681         }
23682     },
23683
23684     // private
23685     getRepairXY : function(e, data){
23686         return this.el.getXY();  
23687     },
23688
23689     // private
23690     onInvalidDrop : function(target, e, id){
23691         this.beforeInvalidDrop(target, e, id);
23692         if(this.cachedTarget){
23693             if(this.cachedTarget.isNotifyTarget){
23694                 this.cachedTarget.notifyOut(this, e, this.dragData);
23695             }
23696             this.cacheTarget = null;
23697         }
23698         this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
23699
23700         if(this.afterInvalidDrop){
23701             /**
23702              * An empty function by default, but provided so that you can perform a custom action
23703              * after an invalid drop has occurred by providing an implementation.
23704              * @param {Event} e The event object
23705              * @param {String} id The id of the dropped element
23706              * @method afterInvalidDrop
23707              */
23708             this.afterInvalidDrop(e, id);
23709         }
23710     },
23711
23712     // private
23713     afterRepair : function(){
23714         if(Roo.enableFx){
23715             this.el.highlight(this.hlColor || "c3daf9");
23716         }
23717         this.dragging = false;
23718     },
23719
23720     /**
23721      * An empty function by default, but provided so that you can perform a custom action after an invalid
23722      * drop has occurred.
23723      * @param {Roo.dd.DragDrop} target The drop target
23724      * @param {Event} e The event object
23725      * @param {String} id The id of the dragged element
23726      * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
23727      */
23728     beforeInvalidDrop : function(target, e, id){
23729         return true;
23730     },
23731
23732     // private
23733     handleMouseDown : function(e){
23734         if(this.dragging) {
23735             return;
23736         }
23737         var data = this.getDragData(e);
23738         if(data && this.onBeforeDrag(data, e) !== false){
23739             this.dragData = data;
23740             this.proxy.stop();
23741             Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
23742         } 
23743     },
23744
23745     /**
23746      * An empty function by default, but provided so that you can perform a custom action before the initial
23747      * drag event begins and optionally cancel it.
23748      * @param {Object} data An object containing arbitrary data to be shared with drop targets
23749      * @param {Event} e The event object
23750      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23751      */
23752     onBeforeDrag : function(data, e){
23753         return true;
23754     },
23755
23756     /**
23757      * An empty function by default, but provided so that you can perform a custom action once the initial
23758      * drag event has begun.  The drag cannot be canceled from this function.
23759      * @param {Number} x The x position of the click on the dragged object
23760      * @param {Number} y The y position of the click on the dragged object
23761      */
23762     onStartDrag : Roo.emptyFn,
23763
23764     // private - YUI override
23765     startDrag : function(x, y){
23766         this.proxy.reset();
23767         this.dragging = true;
23768         this.proxy.update("");
23769         this.onInitDrag(x, y);
23770         this.proxy.show();
23771     },
23772
23773     // private
23774     onInitDrag : function(x, y){
23775         var clone = this.el.dom.cloneNode(true);
23776         clone.id = Roo.id(); // prevent duplicate ids
23777         this.proxy.update(clone);
23778         this.onStartDrag(x, y);
23779         return true;
23780     },
23781
23782     /**
23783      * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
23784      * @return {Roo.dd.StatusProxy} proxy The StatusProxy
23785      */
23786     getProxy : function(){
23787         return this.proxy;  
23788     },
23789
23790     /**
23791      * Hides the drag source's {@link Roo.dd.StatusProxy}
23792      */
23793     hideProxy : function(){
23794         this.proxy.hide();  
23795         this.proxy.reset(true);
23796         this.dragging = false;
23797     },
23798
23799     // private
23800     triggerCacheRefresh : function(){
23801         Roo.dd.DDM.refreshCache(this.groups);
23802     },
23803
23804     // private - override to prevent hiding
23805     b4EndDrag: function(e) {
23806     },
23807
23808     // private - override to prevent moving
23809     endDrag : function(e){
23810         this.onEndDrag(this.dragData, e);
23811     },
23812
23813     // private
23814     onEndDrag : function(data, e){
23815     },
23816     
23817     // private - pin to cursor
23818     autoOffset : function(x, y) {
23819         this.setDelta(-12, -20);
23820     }    
23821 });/*
23822  * Based on:
23823  * Ext JS Library 1.1.1
23824  * Copyright(c) 2006-2007, Ext JS, LLC.
23825  *
23826  * Originally Released Under LGPL - original licence link has changed is not relivant.
23827  *
23828  * Fork - LGPL
23829  * <script type="text/javascript">
23830  */
23831
23832
23833 /**
23834  * @class Roo.dd.DropTarget
23835  * @extends Roo.dd.DDTarget
23836  * A simple class that provides the basic implementation needed to make any element a drop target that can have
23837  * draggable items dropped onto it.  The drop has no effect until an implementation of notifyDrop is provided.
23838  * @constructor
23839  * @param {String/HTMLElement/Element} el The container element
23840  * @param {Object} config
23841  */
23842 Roo.dd.DropTarget = function(el, config){
23843     this.el = Roo.get(el);
23844     
23845     var listeners = false; ;
23846     if (config && config.listeners) {
23847         listeners= config.listeners;
23848         delete config.listeners;
23849     }
23850     Roo.apply(this, config);
23851     
23852     if(this.containerScroll){
23853         Roo.dd.ScrollManager.register(this.el);
23854     }
23855     this.addEvents( {
23856          /**
23857          * @scope Roo.dd.DropTarget
23858          */
23859          
23860          /**
23861          * @event enter
23862          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
23863          * target.  This default implementation adds the CSS class specified by overClass (if any) to the drop element
23864          * and returns the dropAllowed config value.  This method should be overridden if drop validation is required.
23865          * 
23866          * IMPORTANT : it should set  this.valid to true|false
23867          * 
23868          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23869          * @param {Event} e The event
23870          * @param {Object} data An object containing arbitrary data supplied by the drag source
23871          */
23872         "enter" : true,
23873         
23874          /**
23875          * @event over
23876          * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
23877          * This method will be called on every mouse movement while the drag source is over the drop target.
23878          * This default implementation simply returns the dropAllowed config value.
23879          * 
23880          * IMPORTANT : it should set  this.valid to true|false
23881          * 
23882          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23883          * @param {Event} e The event
23884          * @param {Object} data An object containing arbitrary data supplied by the drag source
23885          
23886          */
23887         "over" : true,
23888         /**
23889          * @event out
23890          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
23891          * out of the target without dropping.  This default implementation simply removes the CSS class specified by
23892          * overClass (if any) from the drop element.
23893          * 
23894          * 
23895          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23896          * @param {Event} e The event
23897          * @param {Object} data An object containing arbitrary data supplied by the drag source
23898          */
23899          "out" : true,
23900          
23901         /**
23902          * @event drop
23903          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
23904          * been dropped on it.  This method has no default implementation and returns false, so you must provide an
23905          * implementation that does something to process the drop event and returns true so that the drag source's
23906          * repair action does not run.
23907          * 
23908          * IMPORTANT : it should set this.success
23909          * 
23910          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23911          * @param {Event} e The event
23912          * @param {Object} data An object containing arbitrary data supplied by the drag source
23913         */
23914          "drop" : true
23915     });
23916             
23917      
23918     Roo.dd.DropTarget.superclass.constructor.call(  this, 
23919         this.el.dom, 
23920         this.ddGroup || this.group,
23921         {
23922             isTarget: true,
23923             listeners : listeners || {} 
23924            
23925         
23926         }
23927     );
23928
23929 };
23930
23931 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
23932     /**
23933      * @cfg {String} overClass
23934      * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
23935      */
23936      /**
23937      * @cfg {String} ddGroup
23938      * The drag drop group to handle drop events for
23939      */
23940      
23941     /**
23942      * @cfg {String} dropAllowed
23943      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
23944      */
23945     dropAllowed : "x-dd-drop-ok",
23946     /**
23947      * @cfg {String} dropNotAllowed
23948      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
23949      */
23950     dropNotAllowed : "x-dd-drop-nodrop",
23951     /**
23952      * @cfg {boolean} success
23953      * set this after drop listener.. 
23954      */
23955     success : false,
23956     /**
23957      * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
23958      * if the drop point is valid for over/enter..
23959      */
23960     valid : false,
23961     // private
23962     isTarget : true,
23963
23964     // private
23965     isNotifyTarget : true,
23966     
23967     /**
23968      * @hide
23969      */
23970     notifyEnter : function(dd, e, data)
23971     {
23972         this.valid = true;
23973         this.fireEvent('enter', dd, e, data);
23974         if(this.overClass){
23975             this.el.addClass(this.overClass);
23976         }
23977         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
23978             this.valid ? this.dropAllowed : this.dropNotAllowed
23979         );
23980     },
23981
23982     /**
23983      * @hide
23984      */
23985     notifyOver : function(dd, e, data)
23986     {
23987         this.valid = true;
23988         this.fireEvent('over', dd, e, data);
23989         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
23990             this.valid ? this.dropAllowed : this.dropNotAllowed
23991         );
23992     },
23993
23994     /**
23995      * @hide
23996      */
23997     notifyOut : function(dd, e, data)
23998     {
23999         this.fireEvent('out', dd, e, data);
24000         if(this.overClass){
24001             this.el.removeClass(this.overClass);
24002         }
24003     },
24004
24005     /**
24006      * @hide
24007      */
24008     notifyDrop : function(dd, e, data)
24009     {
24010         this.success = false;
24011         this.fireEvent('drop', dd, e, data);
24012         return this.success;
24013     }
24014 });/*
24015  * Based on:
24016  * Ext JS Library 1.1.1
24017  * Copyright(c) 2006-2007, Ext JS, LLC.
24018  *
24019  * Originally Released Under LGPL - original licence link has changed is not relivant.
24020  *
24021  * Fork - LGPL
24022  * <script type="text/javascript">
24023  */
24024
24025
24026 /**
24027  * @class Roo.dd.DragZone
24028  * @extends Roo.dd.DragSource
24029  * This class provides a container DD instance that proxies for multiple child node sources.<br />
24030  * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
24031  * @constructor
24032  * @param {String/HTMLElement/Element} el The container element
24033  * @param {Object} config
24034  */
24035 Roo.dd.DragZone = function(el, config){
24036     Roo.dd.DragZone.superclass.constructor.call(this, el, config);
24037     if(this.containerScroll){
24038         Roo.dd.ScrollManager.register(this.el);
24039     }
24040 };
24041
24042 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
24043     /**
24044      * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
24045      * for auto scrolling during drag operations.
24046      */
24047     /**
24048      * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
24049      * method after a failed drop (defaults to "c3daf9" - light blue)
24050      */
24051
24052     /**
24053      * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
24054      * for a valid target to drag based on the mouse down. Override this method
24055      * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
24056      * object has a "ddel" attribute (with an HTML Element) for other functions to work.
24057      * @param {EventObject} e The mouse down event
24058      * @return {Object} The dragData
24059      */
24060     getDragData : function(e){
24061         return Roo.dd.Registry.getHandleFromEvent(e);
24062     },
24063     
24064     /**
24065      * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
24066      * this.dragData.ddel
24067      * @param {Number} x The x position of the click on the dragged object
24068      * @param {Number} y The y position of the click on the dragged object
24069      * @return {Boolean} true to continue the drag, false to cancel
24070      */
24071     onInitDrag : function(x, y){
24072         this.proxy.update(this.dragData.ddel.cloneNode(true));
24073         this.onStartDrag(x, y);
24074         return true;
24075     },
24076     
24077     /**
24078      * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel 
24079      */
24080     afterRepair : function(){
24081         if(Roo.enableFx){
24082             Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
24083         }
24084         this.dragging = false;
24085     },
24086
24087     /**
24088      * Called before a repair of an invalid drop to get the XY to animate to. By default returns
24089      * the XY of this.dragData.ddel
24090      * @param {EventObject} e The mouse up event
24091      * @return {Array} The xy location (e.g. [100, 200])
24092      */
24093     getRepairXY : function(e){
24094         return Roo.Element.fly(this.dragData.ddel).getXY();  
24095     }
24096 });/*
24097  * Based on:
24098  * Ext JS Library 1.1.1
24099  * Copyright(c) 2006-2007, Ext JS, LLC.
24100  *
24101  * Originally Released Under LGPL - original licence link has changed is not relivant.
24102  *
24103  * Fork - LGPL
24104  * <script type="text/javascript">
24105  */
24106 /**
24107  * @class Roo.dd.DropZone
24108  * @extends Roo.dd.DropTarget
24109  * This class provides a container DD instance that proxies for multiple child node targets.<br />
24110  * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
24111  * @constructor
24112  * @param {String/HTMLElement/Element} el The container element
24113  * @param {Object} config
24114  */
24115 Roo.dd.DropZone = function(el, config){
24116     Roo.dd.DropZone.superclass.constructor.call(this, el, config);
24117 };
24118
24119 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
24120     /**
24121      * Returns a custom data object associated with the DOM node that is the target of the event.  By default
24122      * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
24123      * provide your own custom lookup.
24124      * @param {Event} e The event
24125      * @return {Object} data The custom data
24126      */
24127     getTargetFromEvent : function(e){
24128         return Roo.dd.Registry.getTargetFromEvent(e);
24129     },
24130
24131     /**
24132      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
24133      * that it has registered.  This method has no default implementation and should be overridden to provide
24134      * node-specific processing if necessary.
24135      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from 
24136      * {@link #getTargetFromEvent} for this node)
24137      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24138      * @param {Event} e The event
24139      * @param {Object} data An object containing arbitrary data supplied by the drag source
24140      */
24141     onNodeEnter : function(n, dd, e, data){
24142         
24143     },
24144
24145     /**
24146      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
24147      * that it has registered.  The default implementation returns this.dropNotAllowed, so it should be
24148      * overridden to provide the proper feedback.
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      * @return {String} status The CSS class that communicates the drop status back to the source so that the
24155      * underlying {@link Roo.dd.StatusProxy} can be updated
24156      */
24157     onNodeOver : function(n, dd, e, data){
24158         return this.dropAllowed;
24159     },
24160
24161     /**
24162      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
24163      * the drop node without dropping.  This method has no default implementation and should be overridden to provide
24164      * node-specific processing if necessary.
24165      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
24166      * {@link #getTargetFromEvent} for this node)
24167      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24168      * @param {Event} e The event
24169      * @param {Object} data An object containing arbitrary data supplied by the drag source
24170      */
24171     onNodeOut : function(n, dd, e, data){
24172         
24173     },
24174
24175     /**
24176      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
24177      * the drop node.  The default implementation returns false, so it should be overridden to provide the
24178      * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
24179      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
24180      * {@link #getTargetFromEvent} for this node)
24181      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24182      * @param {Event} e The event
24183      * @param {Object} data An object containing arbitrary data supplied by the drag source
24184      * @return {Boolean} True if the drop was valid, else false
24185      */
24186     onNodeDrop : function(n, dd, e, data){
24187         return false;
24188     },
24189
24190     /**
24191      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
24192      * but not over any of its registered drop nodes.  The default implementation returns this.dropNotAllowed, so
24193      * it should be overridden to provide the proper feedback if necessary.
24194      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24195      * @param {Event} e The event
24196      * @param {Object} data An object containing arbitrary data supplied by the drag source
24197      * @return {String} status The CSS class that communicates the drop status back to the source so that the
24198      * underlying {@link Roo.dd.StatusProxy} can be updated
24199      */
24200     onContainerOver : function(dd, e, data){
24201         return this.dropNotAllowed;
24202     },
24203
24204     /**
24205      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
24206      * but not on any of its registered drop nodes.  The default implementation returns false, so it should be
24207      * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
24208      * be able to accept drops.  It should return true when valid so that the drag source's repair action does not run.
24209      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24210      * @param {Event} e The event
24211      * @param {Object} data An object containing arbitrary data supplied by the drag source
24212      * @return {Boolean} True if the drop was valid, else false
24213      */
24214     onContainerDrop : function(dd, e, data){
24215         return false;
24216     },
24217
24218     /**
24219      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
24220      * the zone.  The default implementation returns this.dropNotAllowed and expects that only registered drop
24221      * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
24222      * you should override this method and provide a custom implementation.
24223      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24224      * @param {Event} e The event
24225      * @param {Object} data An object containing arbitrary data supplied by the drag source
24226      * @return {String} status The CSS class that communicates the drop status back to the source so that the
24227      * underlying {@link Roo.dd.StatusProxy} can be updated
24228      */
24229     notifyEnter : function(dd, e, data){
24230         return this.dropNotAllowed;
24231     },
24232
24233     /**
24234      * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
24235      * This method will be called on every mouse movement while the drag source is over the drop zone.
24236      * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
24237      * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
24238      * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
24239      * registered node, it will call {@link #onContainerOver}.
24240      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24241      * @param {Event} e The event
24242      * @param {Object} data An object containing arbitrary data supplied by the drag source
24243      * @return {String} status The CSS class that communicates the drop status back to the source so that the
24244      * underlying {@link Roo.dd.StatusProxy} can be updated
24245      */
24246     notifyOver : function(dd, e, data){
24247         var n = this.getTargetFromEvent(e);
24248         if(!n){ // not over valid drop target
24249             if(this.lastOverNode){
24250                 this.onNodeOut(this.lastOverNode, dd, e, data);
24251                 this.lastOverNode = null;
24252             }
24253             return this.onContainerOver(dd, e, data);
24254         }
24255         if(this.lastOverNode != n){
24256             if(this.lastOverNode){
24257                 this.onNodeOut(this.lastOverNode, dd, e, data);
24258             }
24259             this.onNodeEnter(n, dd, e, data);
24260             this.lastOverNode = n;
24261         }
24262         return this.onNodeOver(n, dd, e, data);
24263     },
24264
24265     /**
24266      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
24267      * out of the zone without dropping.  If the drag source is currently over a registered node, the notification
24268      * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
24269      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
24270      * @param {Event} e The event
24271      * @param {Object} data An object containing arbitrary data supplied by the drag zone
24272      */
24273     notifyOut : function(dd, e, data){
24274         if(this.lastOverNode){
24275             this.onNodeOut(this.lastOverNode, dd, e, data);
24276             this.lastOverNode = null;
24277         }
24278     },
24279
24280     /**
24281      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
24282      * been dropped on it.  The drag zone will look up the target node based on the event passed in, and if there
24283      * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
24284      * otherwise it will call {@link #onContainerDrop}.
24285      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24286      * @param {Event} e The event
24287      * @param {Object} data An object containing arbitrary data supplied by the drag source
24288      * @return {Boolean} True if the drop was valid, else false
24289      */
24290     notifyDrop : function(dd, e, data){
24291         if(this.lastOverNode){
24292             this.onNodeOut(this.lastOverNode, dd, e, data);
24293             this.lastOverNode = null;
24294         }
24295         var n = this.getTargetFromEvent(e);
24296         return n ?
24297             this.onNodeDrop(n, dd, e, data) :
24298             this.onContainerDrop(dd, e, data);
24299     },
24300
24301     // private
24302     triggerCacheRefresh : function(){
24303         Roo.dd.DDM.refreshCache(this.groups);
24304     }  
24305 });