sync
[roojs1] / roojs-core-debug.js
1 /*
2  * Based on:
3  * Ext JS Library 1.1.1
4  * Copyright(c) 2006-2007, Ext JS, LLC.
5  *
6  * Originally Released Under LGPL - original licence link has changed is not relivant.
7  *
8  * Fork - LGPL
9  * <script type="text/javascript">
10  */
11  
12
13
14
15
16 // for old browsers
17 window["undefined"] = window["undefined"];
18
19 /**
20  * @class Roo
21  * Roo core utilities and functions.
22  * @static
23  */
24 var Roo = {}; 
25 /**
26  * Copies all the properties of config to obj.
27  * @param {Object} obj The receiver of the properties
28  * @param {Object} config The source of the properties
29  * @param {Object} defaults A different object that will also be applied for default values
30  * @return {Object} returns obj
31  * @member Roo apply
32  */
33
34  
35 Roo.apply = function(o, c, defaults){
36     if(defaults){
37         // no "this" reference for friendly out of scope calls
38         Roo.apply(o, defaults);
39     }
40     if(o && c && typeof c == 'object'){
41         for(var p in c){
42             o[p] = c[p];
43         }
44     }
45     return o;
46 };
47
48
49 (function(){
50     var idSeed = 0;
51     var ua = navigator.userAgent.toLowerCase();
52
53     var isStrict = document.compatMode == "CSS1Compat",
54         isOpera = ua.indexOf("opera") > -1,
55         isSafari = (/webkit|khtml/).test(ua),
56         isFirefox = ua.indexOf("firefox") > -1,
57         isIE = ua.indexOf("msie") > -1,
58         isIE7 = ua.indexOf("msie 7") > -1,
59         isIE11 = /trident.*rv\:11\./.test(ua),
60         isEdge = ua.indexOf("edge") > -1,
61         isGecko = !isSafari && ua.indexOf("gecko") > -1,
62         isBorderBox = isIE && !isStrict,
63         isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
64         isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
65         isLinux = (ua.indexOf("linux") != -1),
66         isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
67         isIOS = /iphone|ipad/.test(ua),
68         isAndroid = /android/.test(ua),
69         isTouch =  (function() {
70             try {
71                 if (ua.indexOf('chrome') != -1 && ua.indexOf('android') == -1) {
72                     window.addEventListener('touchstart', function __set_has_touch__ () {
73                         Roo.isTouch = true;
74                         window.removeEventListener('touchstart', __set_has_touch__);
75                     });
76                     return false; // no touch on chrome!?
77                 }
78                 document.createEvent("TouchEvent");  
79                 return true;  
80             } catch (e) {  
81                 return false;  
82             } 
83             
84         })();
85     // remove css image flicker
86         if(isIE && !isIE7){
87         try{
88             document.execCommand("BackgroundImageCache", false, true);
89         }catch(e){}
90     }
91     
92     Roo.apply(Roo, {
93         /**
94          * True if the browser is in strict mode
95          * @type Boolean
96          */
97         isStrict : isStrict,
98         /**
99          * True if the page is running over SSL
100          * @type Boolean
101          */
102         isSecure : isSecure,
103         /**
104          * True when the document is fully initialized and ready for action
105          * @type Boolean
106          */
107         isReady : false,
108         /**
109          * Turn on debugging output (currently only the factory uses this)
110          * @type Boolean
111          */
112         
113         debug: false,
114
115         /**
116          * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
117          * @type Boolean
118          */
119         enableGarbageCollector : true,
120
121         /**
122          * True to automatically purge event listeners after uncaching an element (defaults to false).
123          * Note: this only happens if enableGarbageCollector is true.
124          * @type Boolean
125          */
126         enableListenerCollection:false,
127
128         /**
129          * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
130          * the IE insecure content warning (defaults to javascript:false).
131          * @type String
132          */
133         SSL_SECURE_URL : "javascript:false",
134
135         /**
136          * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
137          * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
138          * @type String
139          */
140         BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
141
142         emptyFn : function(){},
143         
144         /**
145          * Copies all the properties of config to obj if they don't already exist.
146          * @param {Object} obj The receiver of the properties
147          * @param {Object} config The source of the properties
148          * @return {Object} returns obj
149          */
150         applyIf : function(o, c){
151             if(o && c){
152                 for(var p in c){
153                     if(typeof o[p] == "undefined"){ o[p] = c[p]; }
154                 }
155             }
156             return o;
157         },
158
159         /**
160          * Applies event listeners to elements by selectors when the document is ready.
161          * The event name is specified with an @ suffix.
162 <pre><code>
163 Roo.addBehaviors({
164    // add a listener for click on all anchors in element with id foo
165    '#foo a@click' : function(e, t){
166        // do something
167    },
168
169    // add the same listener to multiple selectors (separated by comma BEFORE the @)
170    '#foo a, #bar span.some-class@mouseover' : function(){
171        // do something
172    }
173 });
174 </code></pre>
175          * @param {Object} obj The list of behaviors to apply
176          */
177         addBehaviors : function(o){
178             if(!Roo.isReady){
179                 Roo.onReady(function(){
180                     Roo.addBehaviors(o);
181                 });
182                 return;
183             }
184             var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
185             for(var b in o){
186                 var parts = b.split('@');
187                 if(parts[1]){ // for Object prototype breakers
188                     var s = parts[0];
189                     if(!cache[s]){
190                         cache[s] = Roo.select(s);
191                     }
192                     cache[s].on(parts[1], o[b]);
193                 }
194             }
195             cache = null;
196         },
197
198         /**
199          * Generates unique ids. If the element already has an id, it is unchanged
200          * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
201          * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
202          * @return {String} The generated Id.
203          */
204         id : function(el, prefix){
205             prefix = prefix || "roo-gen";
206             el = Roo.getDom(el);
207             var id = prefix + (++idSeed);
208             return el ? (el.id ? el.id : (el.id = id)) : id;
209         },
210          
211        
212         /**
213          * Extends one class with another class and optionally overrides members with the passed literal. This class
214          * also adds the function "override()" to the class that can be used to override
215          * members on an instance.
216          * @param {Object} subclass The class inheriting the functionality
217          * @param {Object} superclass The class being extended
218          * @param {Object} overrides (optional) A literal with members
219          * @method extend
220          */
221         extend : function(){
222             // inline overrides
223             var io = function(o){
224                 for(var m in o){
225                     this[m] = o[m];
226                 }
227             };
228             return function(sb, sp, overrides){
229                 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
230                     overrides = sp;
231                     sp = sb;
232                     sb = function(){sp.apply(this, arguments);};
233                 }
234                 var F = function(){}, sbp, spp = sp.prototype;
235                 F.prototype = spp;
236                 sbp = sb.prototype = new F();
237                 sbp.constructor=sb;
238                 sb.superclass=spp;
239                 
240                 if(spp.constructor == Object.prototype.constructor){
241                     spp.constructor=sp;
242                    
243                 }
244                 
245                 sb.override = function(o){
246                     Roo.override(sb, o);
247                 };
248                 sbp.override = io;
249                 Roo.override(sb, overrides);
250                 return sb;
251             };
252         }(),
253
254         /**
255          * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
256          * Usage:<pre><code>
257 Roo.override(MyClass, {
258     newMethod1: function(){
259         // etc.
260     },
261     newMethod2: function(foo){
262         // etc.
263     }
264 });
265  </code></pre>
266          * @param {Object} origclass The class to override
267          * @param {Object} overrides The list of functions to add to origClass.  This should be specified as an object literal
268          * containing one or more methods.
269          * @method override
270          */
271         override : function(origclass, overrides){
272             if(overrides){
273                 var p = origclass.prototype;
274                 for(var method in overrides){
275                     p[method] = overrides[method];
276                 }
277             }
278         },
279         /**
280          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
281          * <pre><code>
282 Roo.namespace('Company', 'Company.data');
283 Company.Widget = function() { ... }
284 Company.data.CustomStore = function(config) { ... }
285 </code></pre>
286          * @param {String} namespace1
287          * @param {String} namespace2
288          * @param {String} etc
289          * @method namespace
290          */
291         namespace : function(){
292             var a=arguments, o=null, i, j, d, rt;
293             for (i=0; i<a.length; ++i) {
294                 d=a[i].split(".");
295                 rt = d[0];
296                 /** eval:var:o */
297                 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
298                 for (j=1; j<d.length; ++j) {
299                     o[d[j]]=o[d[j]] || {};
300                     o=o[d[j]];
301                 }
302             }
303         },
304         /**
305          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
306          * <pre><code>
307 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
308 Roo.factory(conf, Roo.data);
309 </code></pre>
310          * @param {String} classname
311          * @param {String} namespace (optional)
312          * @method factory
313          */
314          
315         factory : function(c, ns)
316         {
317             // no xtype, no ns or c.xns - or forced off by c.xns
318             if (!c.xtype   || (!ns && !c.xns) ||  (c.xns === false)) { // not enough info...
319                 return c;
320             }
321             ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
322             if (c.constructor == ns[c.xtype]) {// already created...
323                 return c;
324             }
325             if (ns[c.xtype]) {
326                 if (Roo.debug) { Roo.log("Roo.Factory(" + c.xtype + ")"); }
327                 var ret = new ns[c.xtype](c);
328                 ret.xns = false;
329                 return ret;
330             }
331             c.xns = false; // prevent recursion..
332             return c;
333         },
334          /**
335          * Logs to console if it can.
336          *
337          * @param {String|Object} string
338          * @method log
339          */
340         log : function(s)
341         {
342             if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
343                 return; // alerT?
344             }
345             
346             console.log(s);
347         },
348         /**
349          * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2".  Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
350          * @param {Object} o
351          * @return {String}
352          */
353         urlEncode : function(o){
354             if(!o){
355                 return "";
356             }
357             var buf = [];
358             for(var key in o){
359                 var ov = o[key], k = Roo.encodeURIComponent(key);
360                 var type = typeof ov;
361                 if(type == 'undefined'){
362                     buf.push(k, "=&");
363                 }else if(type != "function" && type != "object"){
364                     buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
365                 }else if(ov instanceof Array){
366                     if (ov.length) {
367                             for(var i = 0, len = ov.length; i < len; i++) {
368                                 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
369                             }
370                         } else {
371                             buf.push(k, "=&");
372                         }
373                 }
374             }
375             buf.pop();
376             return buf.join("");
377         },
378          /**
379          * Safe version of encodeURIComponent
380          * @param {String} data 
381          * @return {String} 
382          */
383         
384         encodeURIComponent : function (data)
385         {
386             try {
387                 return encodeURIComponent(data);
388             } catch(e) {} // should be an uri encode error.
389             
390             if (data == '' || data == null){
391                return '';
392             }
393             // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
394             function nibble_to_hex(nibble){
395                 var chars = '0123456789ABCDEF';
396                 return chars.charAt(nibble);
397             }
398             data = data.toString();
399             var buffer = '';
400             for(var i=0; i<data.length; i++){
401                 var c = data.charCodeAt(i);
402                 var bs = new Array();
403                 if (c > 0x10000){
404                         // 4 bytes
405                     bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
406                     bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
407                     bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
408                     bs[3] = 0x80 | (c & 0x3F);
409                 }else if (c > 0x800){
410                          // 3 bytes
411                     bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
412                     bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
413                     bs[2] = 0x80 | (c & 0x3F);
414                 }else if (c > 0x80){
415                        // 2 bytes
416                     bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
417                     bs[1] = 0x80 | (c & 0x3F);
418                 }else{
419                         // 1 byte
420                     bs[0] = c;
421                 }
422                 for(var j=0; j<bs.length; j++){
423                     var b = bs[j];
424                     var hex = nibble_to_hex((b & 0xF0) >>> 4) 
425                             + nibble_to_hex(b &0x0F);
426                     buffer += '%'+hex;
427                }
428             }
429             return buffer;    
430              
431         },
432
433         /**
434          * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
435          * @param {String} string
436          * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
437          * @return {Object} A literal with members
438          */
439         urlDecode : function(string, overwrite){
440             if(!string || !string.length){
441                 return {};
442             }
443             var obj = {};
444             var pairs = string.split('&');
445             var pair, name, value;
446             for(var i = 0, len = pairs.length; i < len; i++){
447                 pair = pairs[i].split('=');
448                 name = decodeURIComponent(pair[0]);
449                 value = decodeURIComponent(pair[1]);
450                 if(overwrite !== true){
451                     if(typeof obj[name] == "undefined"){
452                         obj[name] = value;
453                     }else if(typeof obj[name] == "string"){
454                         obj[name] = [obj[name]];
455                         obj[name].push(value);
456                     }else{
457                         obj[name].push(value);
458                     }
459                 }else{
460                     obj[name] = value;
461                 }
462             }
463             return obj;
464         },
465
466         /**
467          * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
468          * passed array is not really an array, your function is called once with it.
469          * The supplied function is called with (Object item, Number index, Array allItems).
470          * @param {Array/NodeList/Mixed} array
471          * @param {Function} fn
472          * @param {Object} scope
473          */
474         each : function(array, fn, scope){
475             if(typeof array.length == "undefined" || typeof array == "string"){
476                 array = [array];
477             }
478             for(var i = 0, len = array.length; i < len; i++){
479                 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
480             }
481         },
482
483         // deprecated
484         combine : function(){
485             var as = arguments, l = as.length, r = [];
486             for(var i = 0; i < l; i++){
487                 var a = as[i];
488                 if(a instanceof Array){
489                     r = r.concat(a);
490                 }else if(a.length !== undefined && !a.substr){
491                     r = r.concat(Array.prototype.slice.call(a, 0));
492                 }else{
493                     r.push(a);
494                 }
495             }
496             return r;
497         },
498
499         /**
500          * Escapes the passed string for use in a regular expression
501          * @param {String} str
502          * @return {String}
503          */
504         escapeRe : function(s) {
505             return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
506         },
507
508         // internal
509         callback : function(cb, scope, args, delay){
510             if(typeof cb == "function"){
511                 if(delay){
512                     cb.defer(delay, scope, args || []);
513                 }else{
514                     cb.apply(scope, args || []);
515                 }
516             }
517         },
518
519         /**
520          * Return the dom node for the passed string (id), dom node, or Roo.Element
521          * @param {String/HTMLElement/Roo.Element} el
522          * @return HTMLElement
523          */
524         getDom : function(el){
525             if(!el){
526                 return null;
527             }
528             return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
529         },
530
531         /**
532         * Shorthand for {@link Roo.ComponentMgr#get}
533         * @param {String} id
534         * @return Roo.Component
535         */
536         getCmp : function(id){
537             return Roo.ComponentMgr.get(id);
538         },
539          
540         num : function(v, defaultValue){
541             if(typeof v != 'number'){
542                 return defaultValue;
543             }
544             return v;
545         },
546
547         destroy : function(){
548             for(var i = 0, a = arguments, len = a.length; i < len; i++) {
549                 var as = a[i];
550                 if(as){
551                     if(as.dom){
552                         as.removeAllListeners();
553                         as.remove();
554                         continue;
555                     }
556                     if(typeof as.purgeListeners == 'function'){
557                         as.purgeListeners();
558                     }
559                     if(typeof as.destroy == 'function'){
560                         as.destroy();
561                     }
562                 }
563             }
564         },
565
566         // inpired by a similar function in mootools library
567         /**
568          * Returns the type of object that is passed in. If the object passed in is null or undefined it
569          * return false otherwise it returns one of the following values:<ul>
570          * <li><b>string</b>: If the object passed is a string</li>
571          * <li><b>number</b>: If the object passed is a number</li>
572          * <li><b>boolean</b>: If the object passed is a boolean value</li>
573          * <li><b>function</b>: If the object passed is a function reference</li>
574          * <li><b>object</b>: If the object passed is an object</li>
575          * <li><b>array</b>: If the object passed is an array</li>
576          * <li><b>regexp</b>: If the object passed is a regular expression</li>
577          * <li><b>element</b>: If the object passed is a DOM Element</li>
578          * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
579          * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
580          * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
581          * @param {Mixed} object
582          * @return {String}
583          */
584         type : function(o){
585             if(o === undefined || o === null){
586                 return false;
587             }
588             if(o.htmlElement){
589                 return 'element';
590             }
591             var t = typeof o;
592             if(t == 'object' && o.nodeName) {
593                 switch(o.nodeType) {
594                     case 1: return 'element';
595                     case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
596                 }
597             }
598             if(t == 'object' || t == 'function') {
599                 switch(o.constructor) {
600                     case Array: return 'array';
601                     case RegExp: return 'regexp';
602                 }
603                 if(typeof o.length == 'number' && typeof o.item == 'function') {
604                     return 'nodelist';
605                 }
606             }
607             return t;
608         },
609
610         /**
611          * Returns true if the passed value is null, undefined or an empty string (optional).
612          * @param {Mixed} value The value to test
613          * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
614          * @return {Boolean}
615          */
616         isEmpty : function(v, allowBlank){
617             return v === null || v === undefined || (!allowBlank ? v === '' : false);
618         },
619         
620         /** @type Boolean */
621         isOpera : isOpera,
622         /** @type Boolean */
623         isSafari : isSafari,
624         /** @type Boolean */
625         isFirefox : isFirefox,
626         /** @type Boolean */
627         isIE : isIE,
628         /** @type Boolean */
629         isIE7 : isIE7,
630         /** @type Boolean */
631         isIE11 : isIE11,
632         /** @type Boolean */
633         isEdge : isEdge,
634         /** @type Boolean */
635         isGecko : isGecko,
636         /** @type Boolean */
637         isBorderBox : isBorderBox,
638         /** @type Boolean */
639         isWindows : isWindows,
640         /** @type Boolean */
641         isLinux : isLinux,
642         /** @type Boolean */
643         isMac : isMac,
644         /** @type Boolean */
645         isIOS : isIOS,
646         /** @type Boolean */
647         isAndroid : isAndroid,
648         /** @type Boolean */
649         isTouch : isTouch,
650
651         /**
652          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
653          * you may want to set this to true.
654          * @type Boolean
655          */
656         useShims : ((isIE && !isIE7) || (isGecko && isMac)),
657         
658         
659                 
660         /**
661          * Selects a single element as a Roo Element
662          * This is about as close as you can get to jQuery's $('do crazy stuff')
663          * @param {String} selector The selector/xpath query
664          * @param {Node} root (optional) The start of the query (defaults to document).
665          * @return {Roo.Element}
666          */
667         selectNode : function(selector, root) 
668         {
669             var node = Roo.DomQuery.selectNode(selector,root);
670             return node ? Roo.get(node) : new Roo.Element(false);
671         },
672                 /**
673                  * Find the current bootstrap width Grid size
674                  * Note xs is the default for smaller.. - this is currently used by grids to render correct columns
675                  * @returns {String} (xs|sm|md|lg|xl)
676                  */
677                 
678                 getGridSize : function()
679                 {
680                         var w = Roo.lib.Dom.getViewWidth();
681                         switch(true) {
682                                 case w > 1200:
683                                         return 'xl';
684                                 case w > 992:
685                                         return 'lg';
686                                 case w > 768:
687                                         return 'md';
688                                 case w > 576:
689                                         return 'sm';
690                                 default:
691                                         return 'xs'
692                         }
693                         
694                 }
695         
696     });
697
698
699 })();
700
701 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
702                 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
703                 "Roo.app", "Roo.ux" 
704                );
705 /*
706  * Based on:
707  * Ext JS Library 1.1.1
708  * Copyright(c) 2006-2007, Ext JS, LLC.
709  *
710  * Originally Released Under LGPL - original licence link has changed is not relivant.
711  *
712  * Fork - LGPL
713  * <script type="text/javascript">
714  */
715
716 (function() {    
717     // wrappedn so fnCleanup is not in global scope...
718     if(Roo.isIE) {
719         function fnCleanUp() {
720             var p = Function.prototype;
721             delete p.createSequence;
722             delete p.defer;
723             delete p.createDelegate;
724             delete p.createCallback;
725             delete p.createInterceptor;
726
727             window.detachEvent("onunload", fnCleanUp);
728         }
729         window.attachEvent("onunload", fnCleanUp);
730     }
731 })();
732
733
734 /**
735  * @class Function
736  * These functions are available on every Function object (any JavaScript function).
737  */
738 Roo.apply(Function.prototype, {
739      /**
740      * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
741      * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
742      * Will create a function that is bound to those 2 args.
743      * @return {Function} The new function
744     */
745     createCallback : function(/*args...*/){
746         // make args available, in function below
747         var args = arguments;
748         var method = this;
749         return function() {
750             return method.apply(window, args);
751         };
752     },
753
754     /**
755      * Creates a delegate (callback) that sets the scope to obj.
756      * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
757      * Will create a function that is automatically scoped to this.
758      * @param {Object} obj (optional) The object for which the scope is set
759      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
760      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
761      *                                             if a number the args are inserted at the specified position
762      * @return {Function} The new function
763      */
764     createDelegate : function(obj, args, appendArgs){
765         var method = this;
766         return function() {
767             var callArgs = args || arguments;
768             if(appendArgs === true){
769                 callArgs = Array.prototype.slice.call(arguments, 0);
770                 callArgs = callArgs.concat(args);
771             }else if(typeof appendArgs == "number"){
772                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
773                 var applyArgs = [appendArgs, 0].concat(args); // create method call params
774                 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
775             }
776             return method.apply(obj || window, callArgs);
777         };
778     },
779
780     /**
781      * Calls this function after the number of millseconds specified.
782      * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
783      * @param {Object} obj (optional) The object for which the scope is set
784      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
785      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
786      *                                             if a number the args are inserted at the specified position
787      * @return {Number} The timeout id that can be used with clearTimeout
788      */
789     defer : function(millis, obj, args, appendArgs){
790         var fn = this.createDelegate(obj, args, appendArgs);
791         if(millis){
792             return setTimeout(fn, millis);
793         }
794         fn();
795         return 0;
796     },
797     /**
798      * Create a combined function call sequence of the original function + the passed function.
799      * The resulting function returns the results of the original function.
800      * The passed fcn is called with the parameters of the original function
801      * @param {Function} fcn The function to sequence
802      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
803      * @return {Function} The new function
804      */
805     createSequence : function(fcn, scope){
806         if(typeof fcn != "function"){
807             return this;
808         }
809         var method = this;
810         return function() {
811             var retval = method.apply(this || window, arguments);
812             fcn.apply(scope || this || window, arguments);
813             return retval;
814         };
815     },
816
817     /**
818      * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
819      * The resulting function returns the results of the original function.
820      * The passed fcn is called with the parameters of the original function.
821      * @addon
822      * @param {Function} fcn The function to call before the original
823      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
824      * @return {Function} The new function
825      */
826     createInterceptor : function(fcn, scope){
827         if(typeof fcn != "function"){
828             return this;
829         }
830         var method = this;
831         return function() {
832             fcn.target = this;
833             fcn.method = method;
834             if(fcn.apply(scope || this || window, arguments) === false){
835                 return;
836             }
837             return method.apply(this || window, arguments);
838         };
839     }
840 });
841 /*
842  * Based on:
843  * Ext JS Library 1.1.1
844  * Copyright(c) 2006-2007, Ext JS, LLC.
845  *
846  * Originally Released Under LGPL - original licence link has changed is not relivant.
847  *
848  * Fork - LGPL
849  * <script type="text/javascript">
850  */
851
852 Roo.applyIf(String, {
853     
854     /** @scope String */
855     
856     /**
857      * Escapes the passed string for ' and \
858      * @param {String} string The string to escape
859      * @return {String} The escaped string
860      * @static
861      */
862     escape : function(string) {
863         return string.replace(/('|\\)/g, "\\$1");
864     },
865
866     /**
867      * Pads the left side of a string with a specified character.  This is especially useful
868      * for normalizing number and date strings.  Example usage:
869      * <pre><code>
870 var s = String.leftPad('123', 5, '0');
871 // s now contains the string: '00123'
872 </code></pre>
873      * @param {String} string The original string
874      * @param {Number} size The total length of the output string
875      * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
876      * @return {String} The padded string
877      * @static
878      */
879     leftPad : function (val, size, ch) {
880         var result = new String(val);
881         if(ch === null || ch === undefined || ch === '') {
882             ch = " ";
883         }
884         while (result.length < size) {
885             result = ch + result;
886         }
887         return result;
888     },
889
890     /**
891      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
892      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
893      * <pre><code>
894 var cls = 'my-class', text = 'Some text';
895 var s = String.format('<div class="{0}">{1}</div>', cls, text);
896 // s now contains the string: '<div class="my-class">Some text</div>'
897 </code></pre>
898      * @param {String} string The tokenized string to be formatted
899      * @param {String} value1 The value to replace token {0}
900      * @param {String} value2 Etc...
901      * @return {String} The formatted string
902      * @static
903      */
904     format : function(format){
905         var args = Array.prototype.slice.call(arguments, 1);
906         return format.replace(/\{(\d+)\}/g, function(m, i){
907             return Roo.util.Format.htmlEncode(args[i]);
908         });
909     }
910   
911     
912 });
913
914 /**
915  * Utility function that allows you to easily switch a string between two alternating values.  The passed value
916  * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
917  * they are already different, the first value passed in is returned.  Note that this method returns the new value
918  * but does not change the current string.
919  * <pre><code>
920 // alternate sort directions
921 sort = sort.toggle('ASC', 'DESC');
922
923 // instead of conditional logic:
924 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
925 </code></pre>
926  * @param {String} value The value to compare to the current string
927  * @param {String} other The new value to use if the string already equals the first value passed in
928  * @return {String} The new value
929  */
930  
931 String.prototype.toggle = function(value, other){
932     return this == value ? other : value;
933 };
934
935
936 /**
937   * Remove invalid unicode characters from a string 
938   *
939   * @return {String} The clean string
940   */
941 String.prototype.unicodeClean = function () {
942     return this.replace(/[\s\S]/g,
943         function(character) {
944             if (character.charCodeAt()< 256) {
945               return character;
946            }
947            try {
948                 encodeURIComponent(character);
949            } catch(e) { 
950               return '';
951            }
952            return character;
953         }
954     );
955 };
956   
957 /*
958  * Based on:
959  * Ext JS Library 1.1.1
960  * Copyright(c) 2006-2007, Ext JS, LLC.
961  *
962  * Originally Released Under LGPL - original licence link has changed is not relivant.
963  *
964  * Fork - LGPL
965  * <script type="text/javascript">
966  */
967
968  /**
969  * @class Number
970  */
971 Roo.applyIf(Number.prototype, {
972     /**
973      * Checks whether or not the current number is within a desired range.  If the number is already within the
974      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
975      * exceeded.  Note that this method returns the constrained value but does not change the current number.
976      * @param {Number} min The minimum number in the range
977      * @param {Number} max The maximum number in the range
978      * @return {Number} The constrained value if outside the range, otherwise the current value
979      */
980     constrain : function(min, max){
981         return Math.min(Math.max(this, min), max);
982     }
983 });/*
984  * Based on:
985  * Ext JS Library 1.1.1
986  * Copyright(c) 2006-2007, Ext JS, LLC.
987  *
988  * Originally Released Under LGPL - original licence link has changed is not relivant.
989  *
990  * Fork - LGPL
991  * <script type="text/javascript">
992  */
993  /**
994  * @class Array
995  */
996 Roo.applyIf(Array.prototype, {
997     /**
998      * 
999      * Checks whether or not the specified object exists in the array.
1000      * @param {Object} o The object to check for
1001      * @return {Number} The index of o in the array (or -1 if it is not found)
1002      */
1003     indexOf : function(o){
1004        for (var i = 0, len = this.length; i < len; i++){
1005               if(this[i] == o) { return i; }
1006        }
1007            return -1;
1008     },
1009
1010     /**
1011      * Removes the specified object from the array.  If the object is not found nothing happens.
1012      * @param {Object} o The object to remove
1013      */
1014     remove : function(o){
1015        var index = this.indexOf(o);
1016        if(index != -1){
1017            this.splice(index, 1);
1018        }
1019     },
1020     /**
1021      * Map (JS 1.6 compatibility)
1022      * @param {Function} function  to call
1023      */
1024     map : function(fun )
1025     {
1026         var len = this.length >>> 0;
1027         if (typeof fun != "function") {
1028             throw new TypeError();
1029         }
1030         var res = new Array(len);
1031         var thisp = arguments[1];
1032         for (var i = 0; i < len; i++)
1033         {
1034             if (i in this) {
1035                 res[i] = fun.call(thisp, this[i], i, this);
1036             }
1037         }
1038
1039         return res;
1040     },
1041     /**
1042      * equals
1043      * @param {Array} o The array to compare to
1044      * @returns {Boolean} true if the same
1045      */
1046     equals : function(b)
1047     {
1048             // https://stackoverflow.com/questions/3115982/how-to-check-if-two-arrays-are-equal-with-javascript
1049         if (this === b) {
1050             return true;
1051         }
1052         if (b == null) {
1053             return false;
1054         }
1055         if (this.length !== b.length) {
1056             return false;
1057         }
1058           
1059         // sort?? a.sort().equals(b.sort());
1060           
1061         for (var i = 0; i < this.length; ++i) {
1062             if (this[i] !== b[i]) {
1063             return false;
1064             }
1065         }
1066         return true;
1067     } 
1068     
1069     
1070     
1071     
1072 });
1073
1074 Roo.applyIf(Array, {
1075  /**
1076      * from
1077      * @static
1078      * @param {Array} o Or Array like object (eg. nodelist)
1079      * @returns {Array} 
1080      */
1081     from : function(o)
1082     {
1083         var ret= [];
1084     
1085         for (var i =0; i < o.length; i++) { 
1086             ret[i] = o[i];
1087         }
1088         return ret;
1089       
1090     }
1091 });
1092 /*
1093  * Based on:
1094  * Ext JS Library 1.1.1
1095  * Copyright(c) 2006-2007, Ext JS, LLC.
1096  *
1097  * Originally Released Under LGPL - original licence link has changed is not relivant.
1098  *
1099  * Fork - LGPL
1100  * <script type="text/javascript">
1101  */
1102
1103 /**
1104  * @class Date
1105  *
1106  * The date parsing and format syntax is a subset of
1107  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
1108  * supported will provide results equivalent to their PHP versions.
1109  *
1110  * Following is the list of all currently supported formats:
1111  *<pre>
1112 Sample date:
1113 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1114
1115 Format  Output      Description
1116 ------  ----------  --------------------------------------------------------------
1117   d      10         Day of the month, 2 digits with leading zeros
1118   D      Wed        A textual representation of a day, three letters
1119   j      10         Day of the month without leading zeros
1120   l      Wednesday  A full textual representation of the day of the week
1121   S      th         English ordinal day of month suffix, 2 chars (use with j)
1122   w      3          Numeric representation of the day of the week
1123   z      9          The julian date, or day of the year (0-365)
1124   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1125   F      January    A full textual representation of the month
1126   m      01         Numeric representation of a month, with leading zeros
1127   M      Jan        Month name abbreviation, three letters
1128   n      1          Numeric representation of a month, without leading zeros
1129   t      31         Number of days in the given month
1130   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
1131   Y      2007       A full numeric representation of a year, 4 digits
1132   y      07         A two digit representation of a year
1133   a      pm         Lowercase Ante meridiem and Post meridiem
1134   A      PM         Uppercase Ante meridiem and Post meridiem
1135   g      3          12-hour format of an hour without leading zeros
1136   G      15         24-hour format of an hour without leading zeros
1137   h      03         12-hour format of an hour with leading zeros
1138   H      15         24-hour format of an hour with leading zeros
1139   i      05         Minutes with leading zeros
1140   s      01         Seconds, with leading zeros
1141   O      -0600      Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1142   P      -06:00     Difference to Greenwich time (GMT) with colon between hours and minutes
1143   T      CST        Timezone setting of the machine running the code
1144   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
1145 </pre>
1146  *
1147  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1148  * <pre><code>
1149 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1150 document.write(dt.format('Y-m-d'));                         //2007-01-10
1151 document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
1152 document.write(dt.format('l, \\t\\he dS of F Y h:i:s A'));  //Wednesday, the 10th of January 2007 03:05:01 PM
1153  </code></pre>
1154  *
1155  * Here are some standard date/time patterns that you might find helpful.  They
1156  * are not part of the source of Date.js, but to use them you can simply copy this
1157  * block of code into any script that is included after Date.js and they will also become
1158  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
1159  * <pre><code>
1160 Date.patterns = {
1161     ISO8601Long:"Y-m-d H:i:s",
1162     ISO8601Short:"Y-m-d",
1163     ShortDate: "n/j/Y",
1164     LongDate: "l, F d, Y",
1165     FullDateTime: "l, F d, Y g:i:s A",
1166     MonthDay: "F d",
1167     ShortTime: "g:i A",
1168     LongTime: "g:i:s A",
1169     SortableDateTime: "Y-m-d\\TH:i:s",
1170     UniversalSortableDateTime: "Y-m-d H:i:sO",
1171     YearMonth: "F, Y"
1172 };
1173 </code></pre>
1174  *
1175  * Example usage:
1176  * <pre><code>
1177 var dt = new Date();
1178 document.write(dt.format(Date.patterns.ShortDate));
1179  </code></pre>
1180  */
1181
1182 /*
1183  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1184  * They generate precompiled functions from date formats instead of parsing and
1185  * processing the pattern every time you format a date.  These functions are available
1186  * on every Date object (any javascript function).
1187  *
1188  * The original article and download are here:
1189  * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1190  *
1191  */
1192  
1193  
1194  // was in core
1195 /**
1196  Returns the number of milliseconds between this date and date
1197  @param {Date} date (optional) Defaults to now
1198  @return {Number} The diff in milliseconds
1199  @member Date getElapsed
1200  */
1201 Date.prototype.getElapsed = function(date) {
1202         return Math.abs((date || new Date()).getTime()-this.getTime());
1203 };
1204 // was in date file..
1205
1206
1207 // private
1208 Date.parseFunctions = {count:0};
1209 // private
1210 Date.parseRegexes = [];
1211 // private
1212 Date.formatFunctions = {count:0};
1213
1214 // private
1215 Date.prototype.dateFormat = function(format) {
1216     if (Date.formatFunctions[format] == null) {
1217         Date.createNewFormat(format);
1218     }
1219     var func = Date.formatFunctions[format];
1220     return this[func]();
1221 };
1222
1223
1224 /**
1225  * Formats a date given the supplied format string
1226  * @param {String} format The format string
1227  * @return {String} The formatted date
1228  * @method
1229  */
1230 Date.prototype.format = Date.prototype.dateFormat;
1231
1232 // private
1233 Date.createNewFormat = function(format) {
1234     var funcName = "format" + Date.formatFunctions.count++;
1235     Date.formatFunctions[format] = funcName;
1236     var code = "Date.prototype." + funcName + " = function(){return ";
1237     var special = false;
1238     var ch = '';
1239     for (var i = 0; i < format.length; ++i) {
1240         ch = format.charAt(i);
1241         if (!special && ch == "\\") {
1242             special = true;
1243         }
1244         else if (special) {
1245             special = false;
1246             code += "'" + String.escape(ch) + "' + ";
1247         }
1248         else {
1249             code += Date.getFormatCode(ch);
1250         }
1251     }
1252     /** eval:var:zzzzzzzzzzzzz */
1253     eval(code.substring(0, code.length - 3) + ";}");
1254 };
1255
1256 // private
1257 Date.getFormatCode = function(character) {
1258     switch (character) {
1259     case "d":
1260         return "String.leftPad(this.getDate(), 2, '0') + ";
1261     case "D":
1262         return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1263     case "j":
1264         return "this.getDate() + ";
1265     case "l":
1266         return "Date.dayNames[this.getDay()] + ";
1267     case "S":
1268         return "this.getSuffix() + ";
1269     case "w":
1270         return "this.getDay() + ";
1271     case "z":
1272         return "this.getDayOfYear() + ";
1273     case "W":
1274         return "this.getWeekOfYear() + ";
1275     case "F":
1276         return "Date.monthNames[this.getMonth()] + ";
1277     case "m":
1278         return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1279     case "M":
1280         return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1281     case "n":
1282         return "(this.getMonth() + 1) + ";
1283     case "t":
1284         return "this.getDaysInMonth() + ";
1285     case "L":
1286         return "(this.isLeapYear() ? 1 : 0) + ";
1287     case "Y":
1288         return "this.getFullYear() + ";
1289     case "y":
1290         return "('' + this.getFullYear()).substring(2, 4) + ";
1291     case "a":
1292         return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1293     case "A":
1294         return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1295     case "g":
1296         return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1297     case "G":
1298         return "this.getHours() + ";
1299     case "h":
1300         return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1301     case "H":
1302         return "String.leftPad(this.getHours(), 2, '0') + ";
1303     case "i":
1304         return "String.leftPad(this.getMinutes(), 2, '0') + ";
1305     case "s":
1306         return "String.leftPad(this.getSeconds(), 2, '0') + ";
1307     case "O":
1308         return "this.getGMTOffset() + ";
1309     case "P":
1310         return "this.getGMTColonOffset() + ";
1311     case "T":
1312         return "this.getTimezone() + ";
1313     case "Z":
1314         return "(this.getTimezoneOffset() * -60) + ";
1315     default:
1316         return "'" + String.escape(character) + "' + ";
1317     }
1318 };
1319
1320 /**
1321  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1322  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1323  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1324  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1325  * string or the parse operation will fail.
1326  * Example Usage:
1327 <pre><code>
1328 //dt = Fri May 25 2007 (current date)
1329 var dt = new Date();
1330
1331 //dt = Thu May 25 2006 (today's month/day in 2006)
1332 dt = Date.parseDate("2006", "Y");
1333
1334 //dt = Sun Jan 15 2006 (all date parts specified)
1335 dt = Date.parseDate("2006-1-15", "Y-m-d");
1336
1337 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1338 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1339 </code></pre>
1340  * @param {String} input The unparsed date as a string
1341  * @param {String} format The format the date is in
1342  * @return {Date} The parsed date
1343  * @static
1344  */
1345 Date.parseDate = function(input, format) {
1346     if (Date.parseFunctions[format] == null) {
1347         Date.createParser(format);
1348     }
1349     var func = Date.parseFunctions[format];
1350     return Date[func](input);
1351 };
1352 /**
1353  * @private
1354  */
1355
1356 Date.createParser = function(format) {
1357     var funcName = "parse" + Date.parseFunctions.count++;
1358     var regexNum = Date.parseRegexes.length;
1359     var currentGroup = 1;
1360     Date.parseFunctions[format] = funcName;
1361
1362     var code = "Date." + funcName + " = function(input){\n"
1363         + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1364         + "var d = new Date();\n"
1365         + "y = d.getFullYear();\n"
1366         + "m = d.getMonth();\n"
1367         + "d = d.getDate();\n"
1368         + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1369         + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1370         + "if (results && results.length > 0) {";
1371     var regex = "";
1372
1373     var special = false;
1374     var ch = '';
1375     for (var i = 0; i < format.length; ++i) {
1376         ch = format.charAt(i);
1377         if (!special && ch == "\\") {
1378             special = true;
1379         }
1380         else if (special) {
1381             special = false;
1382             regex += String.escape(ch);
1383         }
1384         else {
1385             var obj = Date.formatCodeToRegex(ch, currentGroup);
1386             currentGroup += obj.g;
1387             regex += obj.s;
1388             if (obj.g && obj.c) {
1389                 code += obj.c;
1390             }
1391         }
1392     }
1393
1394     code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1395         + "{v = new Date(y, m, d, h, i, s); v.setFullYear(y);}\n"
1396         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1397         + "{v = new Date(y, m, d, h, i); v.setFullYear(y);}\n"
1398         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1399         + "{v = new Date(y, m, d, h); v.setFullYear(y);}\n"
1400         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1401         + "{v = new Date(y, m, d); v.setFullYear(y);}\n"
1402         + "else if (y >= 0 && m >= 0)\n"
1403         + "{v = new Date(y, m); v.setFullYear(y);}\n"
1404         + "else if (y >= 0)\n"
1405         + "{v = new Date(y); v.setFullYear(y);}\n"
1406         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1407         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1408         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1409         + ";}";
1410
1411     Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1412     /** eval:var:zzzzzzzzzzzzz */
1413     eval(code);
1414 };
1415
1416 // private
1417 Date.formatCodeToRegex = function(character, currentGroup) {
1418     switch (character) {
1419     case "D":
1420         return {g:0,
1421         c:null,
1422         s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1423     case "j":
1424         return {g:1,
1425             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1426             s:"(\\d{1,2})"}; // day of month without leading zeroes
1427     case "d":
1428         return {g:1,
1429             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1430             s:"(\\d{2})"}; // day of month with leading zeroes
1431     case "l":
1432         return {g:0,
1433             c:null,
1434             s:"(?:" + Date.dayNames.join("|") + ")"};
1435     case "S":
1436         return {g:0,
1437             c:null,
1438             s:"(?:st|nd|rd|th)"};
1439     case "w":
1440         return {g:0,
1441             c:null,
1442             s:"\\d"};
1443     case "z":
1444         return {g:0,
1445             c:null,
1446             s:"(?:\\d{1,3})"};
1447     case "W":
1448         return {g:0,
1449             c:null,
1450             s:"(?:\\d{2})"};
1451     case "F":
1452         return {g:1,
1453             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1454             s:"(" + Date.monthNames.join("|") + ")"};
1455     case "M":
1456         return {g:1,
1457             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1458             s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1459     case "n":
1460         return {g:1,
1461             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1462             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1463     case "m":
1464         return {g:1,
1465             c:"m = Math.max(0,parseInt(results[" + currentGroup + "], 10) - 1);\n",
1466             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1467     case "t":
1468         return {g:0,
1469             c:null,
1470             s:"\\d{1,2}"};
1471     case "L":
1472         return {g:0,
1473             c:null,
1474             s:"(?:1|0)"};
1475     case "Y":
1476         return {g:1,
1477             c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1478             s:"(\\d{4})"};
1479     case "y":
1480         return {g:1,
1481             c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1482                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1483             s:"(\\d{1,2})"};
1484     case "a":
1485         return {g:1,
1486             c:"if (results[" + currentGroup + "] == 'am') {\n"
1487                 + "if (h == 12) { h = 0; }\n"
1488                 + "} else { if (h < 12) { h += 12; }}",
1489             s:"(am|pm)"};
1490     case "A":
1491         return {g:1,
1492             c:"if (results[" + currentGroup + "] == 'AM') {\n"
1493                 + "if (h == 12) { h = 0; }\n"
1494                 + "} else { if (h < 12) { h += 12; }}",
1495             s:"(AM|PM)"};
1496     case "g":
1497     case "G":
1498         return {g:1,
1499             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1500             s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
1501     case "h":
1502     case "H":
1503         return {g:1,
1504             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1505             s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
1506     case "i":
1507         return {g:1,
1508             c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1509             s:"(\\d{2})"};
1510     case "s":
1511         return {g:1,
1512             c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1513             s:"(\\d{2})"};
1514     case "O":
1515         return {g:1,
1516             c:[
1517                 "o = results[", currentGroup, "];\n",
1518                 "var sn = o.substring(0,1);\n", // get + / - sign
1519                 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1520                 "var mn = o.substring(3,5) % 60;\n", // get minutes
1521                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1522                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1523             ].join(""),
1524             s:"([+\-]\\d{2,4})"};
1525     
1526     
1527     case "P":
1528         return {g:1,
1529                 c:[
1530                    "o = results[", currentGroup, "];\n",
1531                    "var sn = o.substring(0,1);\n",
1532                    "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1533                    "var mn = o.substring(4,6) % 60;\n",
1534                    "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1535                         "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1536             ].join(""),
1537             s:"([+\-]\\d{4})"};
1538     case "T":
1539         return {g:0,
1540             c:null,
1541             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1542     case "Z":
1543         return {g:1,
1544             c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1545                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1546             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1547     default:
1548         return {g:0,
1549             c:null,
1550             s:String.escape(character)};
1551     }
1552 };
1553
1554 /**
1555  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1556  * @return {String} The abbreviated timezone name (e.g. 'CST')
1557  */
1558 Date.prototype.getTimezone = function() {
1559     return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1560 };
1561
1562 /**
1563  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1564  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1565  */
1566 Date.prototype.getGMTOffset = function() {
1567     return (this.getTimezoneOffset() > 0 ? "-" : "+")
1568         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1569         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1570 };
1571
1572 /**
1573  * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1574  * @return {String} 2-characters representing hours and 2-characters representing minutes
1575  * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1576  */
1577 Date.prototype.getGMTColonOffset = function() {
1578         return (this.getTimezoneOffset() > 0 ? "-" : "+")
1579                 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1580                 + ":"
1581                 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1582 }
1583
1584 /**
1585  * Get the numeric day number of the year, adjusted for leap year.
1586  * @return {Number} 0 through 364 (365 in leap years)
1587  */
1588 Date.prototype.getDayOfYear = function() {
1589     var num = 0;
1590     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1591     for (var i = 0; i < this.getMonth(); ++i) {
1592         num += Date.daysInMonth[i];
1593     }
1594     return num + this.getDate() - 1;
1595 };
1596
1597 /**
1598  * Get the string representation of the numeric week number of the year
1599  * (equivalent to the format specifier 'W').
1600  * @return {String} '00' through '52'
1601  */
1602 Date.prototype.getWeekOfYear = function() {
1603     // Skip to Thursday of this week
1604     var now = this.getDayOfYear() + (4 - this.getDay());
1605     // Find the first Thursday of the year
1606     var jan1 = new Date(this.getFullYear(), 0, 1);
1607     var then = (7 - jan1.getDay() + 4);
1608     return String.leftPad(((now - then) / 7) + 1, 2, "0");
1609 };
1610
1611 /**
1612  * Whether or not the current date is in a leap year.
1613  * @return {Boolean} True if the current date is in a leap year, else false
1614  */
1615 Date.prototype.isLeapYear = function() {
1616     var year = this.getFullYear();
1617     return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1618 };
1619
1620 /**
1621  * Get the first day of the current month, adjusted for leap year.  The returned value
1622  * is the numeric day index within the week (0-6) which can be used in conjunction with
1623  * the {@link #monthNames} array to retrieve the textual day name.
1624  * Example:
1625  *<pre><code>
1626 var dt = new Date('1/10/2007');
1627 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1628 </code></pre>
1629  * @return {Number} The day number (0-6)
1630  */
1631 Date.prototype.getFirstDayOfMonth = function() {
1632     var day = (this.getDay() - (this.getDate() - 1)) % 7;
1633     return (day < 0) ? (day + 7) : day;
1634 };
1635
1636 /**
1637  * Get the last day of the current month, adjusted for leap year.  The returned value
1638  * is the numeric day index within the week (0-6) which can be used in conjunction with
1639  * the {@link #monthNames} array to retrieve the textual day name.
1640  * Example:
1641  *<pre><code>
1642 var dt = new Date('1/10/2007');
1643 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1644 </code></pre>
1645  * @return {Number} The day number (0-6)
1646  */
1647 Date.prototype.getLastDayOfMonth = function() {
1648     var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1649     return (day < 0) ? (day + 7) : day;
1650 };
1651
1652
1653 /**
1654  * Get the first date of this date's month
1655  * @return {Date}
1656  */
1657 Date.prototype.getFirstDateOfMonth = function() {
1658     return new Date(this.getFullYear(), this.getMonth(), 1);
1659 };
1660
1661 /**
1662  * Get the last date of this date's month
1663  * @return {Date}
1664  */
1665 Date.prototype.getLastDateOfMonth = function() {
1666     return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1667 };
1668 /**
1669  * Get the number of days in the current month, adjusted for leap year.
1670  * @return {Number} The number of days in the month
1671  */
1672 Date.prototype.getDaysInMonth = function() {
1673     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1674     return Date.daysInMonth[this.getMonth()];
1675 };
1676
1677 /**
1678  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1679  * @return {String} 'st, 'nd', 'rd' or 'th'
1680  */
1681 Date.prototype.getSuffix = function() {
1682     switch (this.getDate()) {
1683         case 1:
1684         case 21:
1685         case 31:
1686             return "st";
1687         case 2:
1688         case 22:
1689             return "nd";
1690         case 3:
1691         case 23:
1692             return "rd";
1693         default:
1694             return "th";
1695     }
1696 };
1697
1698 // private
1699 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1700
1701 /**
1702  * An array of textual month names.
1703  * Override these values for international dates, for example...
1704  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1705  * @type Array
1706  * @static
1707  */
1708 Date.monthNames =
1709    ["January",
1710     "February",
1711     "March",
1712     "April",
1713     "May",
1714     "June",
1715     "July",
1716     "August",
1717     "September",
1718     "October",
1719     "November",
1720     "December"];
1721
1722 /**
1723  * An array of textual day names.
1724  * Override these values for international dates, for example...
1725  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1726  * @type Array
1727  * @static
1728  */
1729 Date.dayNames =
1730    ["Sunday",
1731     "Monday",
1732     "Tuesday",
1733     "Wednesday",
1734     "Thursday",
1735     "Friday",
1736     "Saturday"];
1737
1738 // private
1739 Date.y2kYear = 50;
1740 // private
1741 Date.monthNumbers = {
1742     Jan:0,
1743     Feb:1,
1744     Mar:2,
1745     Apr:3,
1746     May:4,
1747     Jun:5,
1748     Jul:6,
1749     Aug:7,
1750     Sep:8,
1751     Oct:9,
1752     Nov:10,
1753     Dec:11};
1754
1755 /**
1756  * Creates and returns a new Date instance with the exact same date value as the called instance.
1757  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1758  * variable will also be changed.  When the intention is to create a new variable that will not
1759  * modify the original instance, you should create a clone.
1760  *
1761  * Example of correctly cloning a date:
1762  * <pre><code>
1763 //wrong way:
1764 var orig = new Date('10/1/2006');
1765 var copy = orig;
1766 copy.setDate(5);
1767 document.write(orig);  //returns 'Thu Oct 05 2006'!
1768
1769 //correct way:
1770 var orig = new Date('10/1/2006');
1771 var copy = orig.clone();
1772 copy.setDate(5);
1773 document.write(orig);  //returns 'Thu Oct 01 2006'
1774 </code></pre>
1775  * @return {Date} The new Date instance
1776  */
1777 Date.prototype.clone = function() {
1778         return new Date(this.getTime());
1779 };
1780
1781 /**
1782  * Clears any time information from this date
1783  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1784  @return {Date} this or the clone
1785  */
1786 Date.prototype.clearTime = function(clone){
1787     if(clone){
1788         return this.clone().clearTime();
1789     }
1790     this.setHours(0);
1791     this.setMinutes(0);
1792     this.setSeconds(0);
1793     this.setMilliseconds(0);
1794     return this;
1795 };
1796
1797 // private
1798 // safari setMonth is broken -- check that this is only donw once...
1799 if(Roo.isSafari && typeof(Date.brokenSetMonth) == 'undefined'){
1800     Date.brokenSetMonth = Date.prototype.setMonth;
1801         Date.prototype.setMonth = function(num){
1802                 if(num <= -1){
1803                         var n = Math.ceil(-num);
1804                         var back_year = Math.ceil(n/12);
1805                         var month = (n % 12) ? 12 - n % 12 : 0 ;
1806                         this.setFullYear(this.getFullYear() - back_year);
1807                         return Date.brokenSetMonth.call(this, month);
1808                 } else {
1809                         return Date.brokenSetMonth.apply(this, arguments);
1810                 }
1811         };
1812 }
1813
1814 /** Date interval constant 
1815 * @static 
1816 * @type String */
1817 Date.MILLI = "ms";
1818 /** Date interval constant 
1819 * @static 
1820 * @type String */
1821 Date.SECOND = "s";
1822 /** Date interval constant 
1823 * @static 
1824 * @type String */
1825 Date.MINUTE = "mi";
1826 /** Date interval constant 
1827 * @static 
1828 * @type String */
1829 Date.HOUR = "h";
1830 /** Date interval constant 
1831 * @static 
1832 * @type String */
1833 Date.DAY = "d";
1834 /** Date interval constant 
1835 * @static 
1836 * @type String */
1837 Date.MONTH = "mo";
1838 /** Date interval constant 
1839 * @static 
1840 * @type String */
1841 Date.YEAR = "y";
1842
1843 /**
1844  * Provides a convenient method of performing basic date arithmetic.  This method
1845  * does not modify the Date instance being called - it creates and returns
1846  * a new Date instance containing the resulting date value.
1847  *
1848  * Examples:
1849  * <pre><code>
1850 //Basic usage:
1851 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1852 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1853
1854 //Negative values will subtract correctly:
1855 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1856 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1857
1858 //You can even chain several calls together in one line!
1859 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1860 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1861  </code></pre>
1862  *
1863  * @param {String} interval   A valid date interval enum value
1864  * @param {Number} value      The amount to add to the current date
1865  * @return {Date} The new Date instance
1866  */
1867 Date.prototype.add = function(interval, value){
1868   var d = this.clone();
1869   if (!interval || value === 0) { return d; }
1870   switch(interval.toLowerCase()){
1871     case Date.MILLI:
1872       d.setMilliseconds(this.getMilliseconds() + value);
1873       break;
1874     case Date.SECOND:
1875       d.setSeconds(this.getSeconds() + value);
1876       break;
1877     case Date.MINUTE:
1878       d.setMinutes(this.getMinutes() + value);
1879       break;
1880     case Date.HOUR:
1881       d.setHours(this.getHours() + value);
1882       break;
1883     case Date.DAY:
1884       d.setDate(this.getDate() + value);
1885       break;
1886     case Date.MONTH:
1887       var day = this.getDate();
1888       if(day > 28){
1889           day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1890       }
1891       d.setDate(day);
1892       d.setMonth(this.getMonth() + value);
1893       break;
1894     case Date.YEAR:
1895       d.setFullYear(this.getFullYear() + value);
1896       break;
1897   }
1898   return d;
1899 };
1900 /**
1901  * @class Roo.lib.Dom
1902  * @licence LGPL
1903  * @static
1904  * 
1905  * Dom utils (from YIU afaik)
1906  *
1907  * 
1908  **/
1909 Roo.lib.Dom = {
1910     /**
1911      * Get the view width
1912      * @param {Boolean} full True will get the full document, otherwise it's the view width
1913      * @return {Number} The width
1914      */
1915      
1916     getViewWidth : function(full) {
1917         return full ? this.getDocumentWidth() : this.getViewportWidth();
1918     },
1919     /**
1920      * Get the view height
1921      * @param {Boolean} full True will get the full document, otherwise it's the view height
1922      * @return {Number} The height
1923      */
1924     getViewHeight : function(full) {
1925         return full ? this.getDocumentHeight() : this.getViewportHeight();
1926     },
1927     /**
1928      * Get the Full Document height 
1929      * @return {Number} The height
1930      */
1931     getDocumentHeight: function() {
1932         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1933         return Math.max(scrollHeight, this.getViewportHeight());
1934     },
1935     /**
1936      * Get the Full Document width
1937      * @return {Number} The width
1938      */
1939     getDocumentWidth: function() {
1940         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1941         return Math.max(scrollWidth, this.getViewportWidth());
1942     },
1943     /**
1944      * Get the Window Viewport height
1945      * @return {Number} The height
1946      */
1947     getViewportHeight: function() {
1948         var height = self.innerHeight;
1949         var mode = document.compatMode;
1950
1951         if ((mode || Roo.isIE) && !Roo.isOpera) {
1952             height = (mode == "CSS1Compat") ?
1953                      document.documentElement.clientHeight :
1954                      document.body.clientHeight;
1955         }
1956
1957         return height;
1958     },
1959     /**
1960      * Get the Window Viewport width
1961      * @return {Number} The width
1962      */
1963     getViewportWidth: function() {
1964         var width = self.innerWidth;
1965         var mode = document.compatMode;
1966
1967         if (mode || Roo.isIE) {
1968             width = (mode == "CSS1Compat") ?
1969                     document.documentElement.clientWidth :
1970                     document.body.clientWidth;
1971         }
1972         return width;
1973     },
1974
1975     isAncestor : function(p, c) {
1976         p = Roo.getDom(p);
1977         c = Roo.getDom(c);
1978         if (!p || !c) {
1979             return false;
1980         }
1981
1982         if (p.contains && !Roo.isSafari) {
1983             return p.contains(c);
1984         } else if (p.compareDocumentPosition) {
1985             return !!(p.compareDocumentPosition(c) & 16);
1986         } else {
1987             var parent = c.parentNode;
1988             while (parent) {
1989                 if (parent == p) {
1990                     return true;
1991                 }
1992                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1993                     return false;
1994                 }
1995                 parent = parent.parentNode;
1996             }
1997             return false;
1998         }
1999     },
2000
2001     getRegion : function(el) {
2002         return Roo.lib.Region.getRegion(el);
2003     },
2004
2005     getY : function(el) {
2006         return this.getXY(el)[1];
2007     },
2008
2009     getX : function(el) {
2010         return this.getXY(el)[0];
2011     },
2012
2013     getXY : function(el) {
2014         var p, pe, b, scroll, bd = document.body;
2015         el = Roo.getDom(el);
2016         var fly = Roo.lib.AnimBase.fly;
2017         if (el.getBoundingClientRect) {
2018             b = el.getBoundingClientRect();
2019             scroll = fly(document).getScroll();
2020             return [b.left + scroll.left, b.top + scroll.top];
2021         }
2022         var x = 0, y = 0;
2023
2024         p = el;
2025
2026         var hasAbsolute = fly(el).getStyle("position") == "absolute";
2027
2028         while (p) {
2029
2030             x += p.offsetLeft;
2031             y += p.offsetTop;
2032
2033             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
2034                 hasAbsolute = true;
2035             }
2036
2037             if (Roo.isGecko) {
2038                 pe = fly(p);
2039
2040                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
2041                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
2042
2043
2044                 x += bl;
2045                 y += bt;
2046
2047
2048                 if (p != el && pe.getStyle('overflow') != 'visible') {
2049                     x += bl;
2050                     y += bt;
2051                 }
2052             }
2053             p = p.offsetParent;
2054         }
2055
2056         if (Roo.isSafari && hasAbsolute) {
2057             x -= bd.offsetLeft;
2058             y -= bd.offsetTop;
2059         }
2060
2061         if (Roo.isGecko && !hasAbsolute) {
2062             var dbd = fly(bd);
2063             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
2064             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
2065         }
2066
2067         p = el.parentNode;
2068         while (p && p != bd) {
2069             if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
2070                 x -= p.scrollLeft;
2071                 y -= p.scrollTop;
2072             }
2073             p = p.parentNode;
2074         }
2075         return [x, y];
2076     },
2077  
2078   
2079
2080
2081     setXY : function(el, xy) {
2082         el = Roo.fly(el, '_setXY');
2083         el.position();
2084         var pts = el.translatePoints(xy);
2085         if (xy[0] !== false) {
2086             el.dom.style.left = pts.left + "px";
2087         }
2088         if (xy[1] !== false) {
2089             el.dom.style.top = pts.top + "px";
2090         }
2091     },
2092
2093     setX : function(el, x) {
2094         this.setXY(el, [x, false]);
2095     },
2096
2097     setY : function(el, y) {
2098         this.setXY(el, [false, y]);
2099     }
2100 };
2101 /*
2102  * Portions of this file are based on pieces of Yahoo User Interface Library
2103  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2104  * YUI licensed under the BSD License:
2105  * http://developer.yahoo.net/yui/license.txt
2106  * <script type="text/javascript">
2107  *
2108  */
2109
2110 Roo.lib.Event = function() {
2111     var loadComplete = false;
2112     var listeners = [];
2113     var unloadListeners = [];
2114     var retryCount = 0;
2115     var onAvailStack = [];
2116     var counter = 0;
2117     var lastError = null;
2118
2119     return {
2120         POLL_RETRYS: 200,
2121         POLL_INTERVAL: 20,
2122         EL: 0,
2123         TYPE: 1,
2124         FN: 2,
2125         WFN: 3,
2126         OBJ: 3,
2127         ADJ_SCOPE: 4,
2128         _interval: null,
2129
2130         startInterval: function() {
2131             if (!this._interval) {
2132                 var self = this;
2133                 var callback = function() {
2134                     self._tryPreloadAttach();
2135                 };
2136                 this._interval = setInterval(callback, this.POLL_INTERVAL);
2137
2138             }
2139         },
2140
2141         onAvailable: function(p_id, p_fn, p_obj, p_override) {
2142             onAvailStack.push({ id:         p_id,
2143                 fn:         p_fn,
2144                 obj:        p_obj,
2145                 override:   p_override,
2146                 checkReady: false    });
2147
2148             retryCount = this.POLL_RETRYS;
2149             this.startInterval();
2150         },
2151
2152
2153         addListener: function(el, eventName, fn) {
2154             el = Roo.getDom(el);
2155             if (!el || !fn) {
2156                 return false;
2157             }
2158
2159             if ("unload" == eventName) {
2160                 unloadListeners[unloadListeners.length] =
2161                 [el, eventName, fn];
2162                 return true;
2163             }
2164
2165             var wrappedFn = function(e) {
2166                 return fn(Roo.lib.Event.getEvent(e));
2167             };
2168
2169             var li = [el, eventName, fn, wrappedFn];
2170
2171             var index = listeners.length;
2172             listeners[index] = li;
2173
2174             this.doAdd(el, eventName, wrappedFn, false);
2175             return true;
2176
2177         },
2178
2179
2180         removeListener: function(el, eventName, fn) {
2181             var i, len;
2182
2183             el = Roo.getDom(el);
2184
2185             if(!fn) {
2186                 return this.purgeElement(el, false, eventName);
2187             }
2188
2189
2190             if ("unload" == eventName) {
2191
2192                 for (i = 0,len = unloadListeners.length; i < len; i++) {
2193                     var li = unloadListeners[i];
2194                     if (li &&
2195                         li[0] == el &&
2196                         li[1] == eventName &&
2197                         li[2] == fn) {
2198                         unloadListeners.splice(i, 1);
2199                         return true;
2200                     }
2201                 }
2202
2203                 return false;
2204             }
2205
2206             var cacheItem = null;
2207
2208
2209             var index = arguments[3];
2210
2211             if ("undefined" == typeof index) {
2212                 index = this._getCacheIndex(el, eventName, fn);
2213             }
2214
2215             if (index >= 0) {
2216                 cacheItem = listeners[index];
2217             }
2218
2219             if (!el || !cacheItem) {
2220                 return false;
2221             }
2222
2223             this.doRemove(el, eventName, cacheItem[this.WFN], false);
2224
2225             delete listeners[index][this.WFN];
2226             delete listeners[index][this.FN];
2227             listeners.splice(index, 1);
2228
2229             return true;
2230
2231         },
2232
2233
2234         getTarget: function(ev, resolveTextNode) {
2235             ev = ev.browserEvent || ev;
2236             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2237             var t = ev.target || ev.srcElement;
2238             return this.resolveTextNode(t);
2239         },
2240
2241
2242         resolveTextNode: function(node) {
2243             if (Roo.isSafari && node && 3 == node.nodeType) {
2244                 return node.parentNode;
2245             } else {
2246                 return node;
2247             }
2248         },
2249
2250
2251         getPageX: function(ev) {
2252             ev = ev.browserEvent || ev;
2253             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2254             var x = ev.pageX;
2255             if (!x && 0 !== x) {
2256                 x = ev.clientX || 0;
2257
2258                 if (Roo.isIE) {
2259                     x += this.getScroll()[1];
2260                 }
2261             }
2262
2263             return x;
2264         },
2265
2266
2267         getPageY: function(ev) {
2268             ev = ev.browserEvent || ev;
2269             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2270             var y = ev.pageY;
2271             if (!y && 0 !== y) {
2272                 y = ev.clientY || 0;
2273
2274                 if (Roo.isIE) {
2275                     y += this.getScroll()[0];
2276                 }
2277             }
2278
2279
2280             return y;
2281         },
2282
2283
2284         getXY: function(ev) {
2285             ev = ev.browserEvent || ev;
2286             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2287             return [this.getPageX(ev), this.getPageY(ev)];
2288         },
2289
2290
2291         getRelatedTarget: function(ev) {
2292             ev = ev.browserEvent || ev;
2293             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2294             var t = ev.relatedTarget;
2295             if (!t) {
2296                 if (ev.type == "mouseout") {
2297                     t = ev.toElement;
2298                 } else if (ev.type == "mouseover") {
2299                     t = ev.fromElement;
2300                 }
2301             }
2302
2303             return this.resolveTextNode(t);
2304         },
2305
2306
2307         getTime: function(ev) {
2308             ev = ev.browserEvent || ev;
2309             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2310             if (!ev.time) {
2311                 var t = new Date().getTime();
2312                 try {
2313                     ev.time = t;
2314                 } catch(ex) {
2315                     this.lastError = ex;
2316                     return t;
2317                 }
2318             }
2319
2320             return ev.time;
2321         },
2322
2323
2324         stopEvent: function(ev) {
2325             this.stopPropagation(ev);
2326             this.preventDefault(ev);
2327         },
2328
2329
2330         stopPropagation: function(ev) {
2331             ev = ev.browserEvent || ev;
2332             if (ev.stopPropagation) {
2333                 ev.stopPropagation();
2334             } else {
2335                 ev.cancelBubble = true;
2336             }
2337         },
2338
2339
2340         preventDefault: function(ev) {
2341             ev = ev.browserEvent || ev;
2342             if(ev.preventDefault) {
2343                 ev.preventDefault();
2344             } else {
2345                 ev.returnValue = false;
2346             }
2347         },
2348
2349
2350         getEvent: function(e) {
2351             var ev = e || window.event;
2352             if (!ev) {
2353                 var c = this.getEvent.caller;
2354                 while (c) {
2355                     ev = c.arguments[0];
2356                     if (ev && Event == ev.constructor) {
2357                         break;
2358                     }
2359                     c = c.caller;
2360                 }
2361             }
2362             return ev;
2363         },
2364
2365
2366         getCharCode: function(ev) {
2367             ev = ev.browserEvent || ev;
2368             return ev.charCode || ev.keyCode || 0;
2369         },
2370
2371
2372         _getCacheIndex: function(el, eventName, fn) {
2373             for (var i = 0,len = listeners.length; i < len; ++i) {
2374                 var li = listeners[i];
2375                 if (li &&
2376                     li[this.FN] == fn &&
2377                     li[this.EL] == el &&
2378                     li[this.TYPE] == eventName) {
2379                     return i;
2380                 }
2381             }
2382
2383             return -1;
2384         },
2385
2386
2387         elCache: {},
2388
2389
2390         getEl: function(id) {
2391             return document.getElementById(id);
2392         },
2393
2394
2395         clearCache: function() {
2396         },
2397
2398
2399         _load: function(e) {
2400             loadComplete = true;
2401             var EU = Roo.lib.Event;
2402
2403
2404             if (Roo.isIE) {
2405                 EU.doRemove(window, "load", EU._load);
2406             }
2407         },
2408
2409
2410         _tryPreloadAttach: function() {
2411
2412             if (this.locked) {
2413                 return false;
2414             }
2415
2416             this.locked = true;
2417
2418
2419             var tryAgain = !loadComplete;
2420             if (!tryAgain) {
2421                 tryAgain = (retryCount > 0);
2422             }
2423
2424
2425             var notAvail = [];
2426             for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2427                 var item = onAvailStack[i];
2428                 if (item) {
2429                     var el = this.getEl(item.id);
2430
2431                     if (el) {
2432                         if (!item.checkReady ||
2433                             loadComplete ||
2434                             el.nextSibling ||
2435                             (document && document.body)) {
2436
2437                             var scope = el;
2438                             if (item.override) {
2439                                 if (item.override === true) {
2440                                     scope = item.obj;
2441                                 } else {
2442                                     scope = item.override;
2443                                 }
2444                             }
2445                             item.fn.call(scope, item.obj);
2446                             onAvailStack[i] = null;
2447                         }
2448                     } else {
2449                         notAvail.push(item);
2450                     }
2451                 }
2452             }
2453
2454             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2455
2456             if (tryAgain) {
2457
2458                 this.startInterval();
2459             } else {
2460                 clearInterval(this._interval);
2461                 this._interval = null;
2462             }
2463
2464             this.locked = false;
2465
2466             return true;
2467
2468         },
2469
2470
2471         purgeElement: function(el, recurse, eventName) {
2472             var elListeners = this.getListeners(el, eventName);
2473             if (elListeners) {
2474                 for (var i = 0,len = elListeners.length; i < len; ++i) {
2475                     var l = elListeners[i];
2476                     this.removeListener(el, l.type, l.fn);
2477                 }
2478             }
2479
2480             if (recurse && el && el.childNodes) {
2481                 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2482                     this.purgeElement(el.childNodes[i], recurse, eventName);
2483                 }
2484             }
2485         },
2486
2487
2488         getListeners: function(el, eventName) {
2489             var results = [], searchLists;
2490             if (!eventName) {
2491                 searchLists = [listeners, unloadListeners];
2492             } else if (eventName == "unload") {
2493                 searchLists = [unloadListeners];
2494             } else {
2495                 searchLists = [listeners];
2496             }
2497
2498             for (var j = 0; j < searchLists.length; ++j) {
2499                 var searchList = searchLists[j];
2500                 if (searchList && searchList.length > 0) {
2501                     for (var i = 0,len = searchList.length; i < len; ++i) {
2502                         var l = searchList[i];
2503                         if (l && l[this.EL] === el &&
2504                             (!eventName || eventName === l[this.TYPE])) {
2505                             results.push({
2506                                 type:   l[this.TYPE],
2507                                 fn:     l[this.FN],
2508                                 obj:    l[this.OBJ],
2509                                 adjust: l[this.ADJ_SCOPE],
2510                                 index:  i
2511                             });
2512                         }
2513                     }
2514                 }
2515             }
2516
2517             return (results.length) ? results : null;
2518         },
2519
2520
2521         _unload: function(e) {
2522
2523             var EU = Roo.lib.Event, i, j, l, len, index;
2524
2525             for (i = 0,len = unloadListeners.length; i < len; ++i) {
2526                 l = unloadListeners[i];
2527                 if (l) {
2528                     var scope = window;
2529                     if (l[EU.ADJ_SCOPE]) {
2530                         if (l[EU.ADJ_SCOPE] === true) {
2531                             scope = l[EU.OBJ];
2532                         } else {
2533                             scope = l[EU.ADJ_SCOPE];
2534                         }
2535                     }
2536                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2537                     unloadListeners[i] = null;
2538                     l = null;
2539                     scope = null;
2540                 }
2541             }
2542
2543             unloadListeners = null;
2544
2545             if (listeners && listeners.length > 0) {
2546                 j = listeners.length;
2547                 while (j) {
2548                     index = j - 1;
2549                     l = listeners[index];
2550                     if (l) {
2551                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2552                                 l[EU.FN], index);
2553                     }
2554                     j = j - 1;
2555                 }
2556                 l = null;
2557
2558                 EU.clearCache();
2559             }
2560
2561             EU.doRemove(window, "unload", EU._unload);
2562
2563         },
2564
2565
2566         getScroll: function() {
2567             var dd = document.documentElement, db = document.body;
2568             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2569                 return [dd.scrollTop, dd.scrollLeft];
2570             } else if (db) {
2571                 return [db.scrollTop, db.scrollLeft];
2572             } else {
2573                 return [0, 0];
2574             }
2575         },
2576
2577
2578         doAdd: function () {
2579             if (window.addEventListener) {
2580                 return function(el, eventName, fn, capture) {
2581                     el.addEventListener(eventName, fn, (capture));
2582                 };
2583             } else if (window.attachEvent) {
2584                 return function(el, eventName, fn, capture) {
2585                     el.attachEvent("on" + eventName, fn);
2586                 };
2587             } else {
2588                 return function() {
2589                 };
2590             }
2591         }(),
2592
2593
2594         doRemove: function() {
2595             if (window.removeEventListener) {
2596                 return function (el, eventName, fn, capture) {
2597                     el.removeEventListener(eventName, fn, (capture));
2598                 };
2599             } else if (window.detachEvent) {
2600                 return function (el, eventName, fn) {
2601                     el.detachEvent("on" + eventName, fn);
2602                 };
2603             } else {
2604                 return function() {
2605                 };
2606             }
2607         }()
2608     };
2609     
2610 }();
2611 (function() {     
2612    
2613     var E = Roo.lib.Event;
2614     E.on = E.addListener;
2615     E.un = E.removeListener;
2616
2617     if (document && document.body) {
2618         E._load();
2619     } else {
2620         E.doAdd(window, "load", E._load);
2621     }
2622     E.doAdd(window, "unload", E._unload);
2623     E._tryPreloadAttach();
2624 })();
2625
2626  
2627
2628 (function() {
2629     /**
2630      * @class Roo.lib.Ajax
2631      *
2632      * provide a simple Ajax request utility functions
2633      * 
2634      * Portions of this file are based on pieces of Yahoo User Interface Library
2635     * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2636     * YUI licensed under the BSD License:
2637     * http://developer.yahoo.net/yui/license.txt
2638     * <script type="text/javascript">
2639     *
2640      *
2641      */
2642     Roo.lib.Ajax = {
2643         /**
2644          * @static 
2645          */
2646         request : function(method, uri, cb, data, options) {
2647             if(options){
2648                 var hs = options.headers;
2649                 if(hs){
2650                     for(var h in hs){
2651                         if(hs.hasOwnProperty(h)){
2652                             this.initHeader(h, hs[h], false);
2653                         }
2654                     }
2655                 }
2656                 if(options.xmlData){
2657                     this.initHeader('Content-Type', 'text/xml', false);
2658                     method = 'POST';
2659                     data = options.xmlData;
2660                 }
2661             }
2662
2663             return this.asyncRequest(method, uri, cb, data);
2664         },
2665         /**
2666          * serialize a form
2667          *
2668          * @static
2669          * @param {DomForm} form element
2670          * @return {String} urlencode form output.
2671          */
2672         serializeForm : function(form) {
2673             if(typeof form == 'string') {
2674                 form = (document.getElementById(form) || document.forms[form]);
2675             }
2676
2677             var el, name, val, disabled, data = '', hasSubmit = false;
2678             for (var i = 0; i < form.elements.length; i++) {
2679                 el = form.elements[i];
2680                 disabled = form.elements[i].disabled;
2681                 name = form.elements[i].name;
2682                 val = form.elements[i].value;
2683
2684                 if (!disabled && name){
2685                     switch (el.type)
2686                             {
2687                         case 'select-one':
2688                         case 'select-multiple':
2689                             for (var j = 0; j < el.options.length; j++) {
2690                                 if (el.options[j].selected) {
2691                                     if (Roo.isIE) {
2692                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2693                                     }
2694                                     else {
2695                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2696                                     }
2697                                 }
2698                             }
2699                             break;
2700                         case 'radio':
2701                         case 'checkbox':
2702                             if (el.checked) {
2703                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2704                             }
2705                             break;
2706                         case 'file':
2707
2708                         case undefined:
2709
2710                         case 'reset':
2711
2712                         case 'button':
2713
2714                             break;
2715                         case 'submit':
2716                             if(hasSubmit == false) {
2717                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2718                                 hasSubmit = true;
2719                             }
2720                             break;
2721                         default:
2722                             data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2723                             break;
2724                     }
2725                 }
2726             }
2727             data = data.substr(0, data.length - 1);
2728             return data;
2729         },
2730
2731         headers:{},
2732
2733         hasHeaders:false,
2734
2735         useDefaultHeader:true,
2736
2737         defaultPostHeader:'application/x-www-form-urlencoded',
2738
2739         useDefaultXhrHeader:true,
2740
2741         defaultXhrHeader:'XMLHttpRequest',
2742
2743         hasDefaultHeaders:true,
2744
2745         defaultHeaders:{},
2746
2747         poll:{},
2748
2749         timeout:{},
2750
2751         pollInterval:50,
2752
2753         transactionId:0,
2754
2755         setProgId:function(id)
2756         {
2757             this.activeX.unshift(id);
2758         },
2759
2760         setDefaultPostHeader:function(b)
2761         {
2762             this.useDefaultHeader = b;
2763         },
2764
2765         setDefaultXhrHeader:function(b)
2766         {
2767             this.useDefaultXhrHeader = b;
2768         },
2769
2770         setPollingInterval:function(i)
2771         {
2772             if (typeof i == 'number' && isFinite(i)) {
2773                 this.pollInterval = i;
2774             }
2775         },
2776
2777         createXhrObject:function(transactionId)
2778         {
2779             var obj,http;
2780             try
2781             {
2782
2783                 http = new XMLHttpRequest();
2784
2785                 obj = { conn:http, tId:transactionId };
2786             }
2787             catch(e)
2788             {
2789                 for (var i = 0; i < this.activeX.length; ++i) {
2790                     try
2791                     {
2792
2793                         http = new ActiveXObject(this.activeX[i]);
2794
2795                         obj = { conn:http, tId:transactionId };
2796                         break;
2797                     }
2798                     catch(e) {
2799                     }
2800                 }
2801             }
2802             finally
2803             {
2804                 return obj;
2805             }
2806         },
2807
2808         getConnectionObject:function()
2809         {
2810             var o;
2811             var tId = this.transactionId;
2812
2813             try
2814             {
2815                 o = this.createXhrObject(tId);
2816                 if (o) {
2817                     this.transactionId++;
2818                 }
2819             }
2820             catch(e) {
2821             }
2822             finally
2823             {
2824                 return o;
2825             }
2826         },
2827
2828         asyncRequest:function(method, uri, callback, postData)
2829         {
2830             var o = this.getConnectionObject();
2831
2832             if (!o) {
2833                 return null;
2834             }
2835             else {
2836                 o.conn.open(method, uri, true);
2837
2838                 if (this.useDefaultXhrHeader) {
2839                     if (!this.defaultHeaders['X-Requested-With']) {
2840                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2841                     }
2842                 }
2843
2844                 if(postData && this.useDefaultHeader){
2845                     this.initHeader('Content-Type', this.defaultPostHeader);
2846                 }
2847
2848                  if (this.hasDefaultHeaders || this.hasHeaders) {
2849                     this.setHeader(o);
2850                 }
2851
2852                 this.handleReadyState(o, callback);
2853                 o.conn.send(postData || null);
2854
2855                 return o;
2856             }
2857         },
2858
2859         handleReadyState:function(o, callback)
2860         {
2861             var oConn = this;
2862
2863             if (callback && callback.timeout) {
2864                 
2865                 this.timeout[o.tId] = window.setTimeout(function() {
2866                     oConn.abort(o, callback, true);
2867                 }, callback.timeout);
2868             }
2869
2870             this.poll[o.tId] = window.setInterval(
2871                     function() {
2872                         if (o.conn && o.conn.readyState == 4) {
2873                             window.clearInterval(oConn.poll[o.tId]);
2874                             delete oConn.poll[o.tId];
2875
2876                             if(callback && callback.timeout) {
2877                                 window.clearTimeout(oConn.timeout[o.tId]);
2878                                 delete oConn.timeout[o.tId];
2879                             }
2880
2881                             oConn.handleTransactionResponse(o, callback);
2882                         }
2883                     }
2884                     , this.pollInterval);
2885         },
2886
2887         handleTransactionResponse:function(o, callback, isAbort)
2888         {
2889
2890             if (!callback) {
2891                 this.releaseObject(o);
2892                 return;
2893             }
2894
2895             var httpStatus, responseObject;
2896
2897             try
2898             {
2899                 if (o.conn.status !== undefined && o.conn.status != 0) {
2900                     httpStatus = o.conn.status;
2901                 }
2902                 else {
2903                     httpStatus = 13030;
2904                 }
2905             }
2906             catch(e) {
2907
2908
2909                 httpStatus = 13030;
2910             }
2911
2912             if (httpStatus >= 200 && httpStatus < 300) {
2913                 responseObject = this.createResponseObject(o, callback.argument);
2914                 if (callback.success) {
2915                     if (!callback.scope) {
2916                         callback.success(responseObject);
2917                     }
2918                     else {
2919
2920
2921                         callback.success.apply(callback.scope, [responseObject]);
2922                     }
2923                 }
2924             }
2925             else {
2926                 switch (httpStatus) {
2927
2928                     case 12002:
2929                     case 12029:
2930                     case 12030:
2931                     case 12031:
2932                     case 12152:
2933                     case 13030:
2934                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2935                         if (callback.failure) {
2936                             if (!callback.scope) {
2937                                 callback.failure(responseObject);
2938                             }
2939                             else {
2940                                 callback.failure.apply(callback.scope, [responseObject]);
2941                             }
2942                         }
2943                         break;
2944                     default:
2945                         responseObject = this.createResponseObject(o, callback.argument);
2946                         if (callback.failure) {
2947                             if (!callback.scope) {
2948                                 callback.failure(responseObject);
2949                             }
2950                             else {
2951                                 callback.failure.apply(callback.scope, [responseObject]);
2952                             }
2953                         }
2954                 }
2955             }
2956
2957             this.releaseObject(o);
2958             responseObject = null;
2959         },
2960
2961         createResponseObject:function(o, callbackArg)
2962         {
2963             var obj = {};
2964             var headerObj = {};
2965
2966             try
2967             {
2968                 var headerStr = o.conn.getAllResponseHeaders();
2969                 var header = headerStr.split('\n');
2970                 for (var i = 0; i < header.length; i++) {
2971                     var delimitPos = header[i].indexOf(':');
2972                     if (delimitPos != -1) {
2973                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2974                     }
2975                 }
2976             }
2977             catch(e) {
2978             }
2979
2980             obj.tId = o.tId;
2981             obj.status = o.conn.status;
2982             obj.statusText = o.conn.statusText;
2983             obj.getResponseHeader = headerObj;
2984             obj.getAllResponseHeaders = headerStr;
2985             obj.responseText = o.conn.responseText;
2986             obj.responseXML = o.conn.responseXML;
2987
2988             if (typeof callbackArg !== undefined) {
2989                 obj.argument = callbackArg;
2990             }
2991
2992             return obj;
2993         },
2994
2995         createExceptionObject:function(tId, callbackArg, isAbort)
2996         {
2997             var COMM_CODE = 0;
2998             var COMM_ERROR = 'communication failure';
2999             var ABORT_CODE = -1;
3000             var ABORT_ERROR = 'transaction aborted';
3001
3002             var obj = {};
3003
3004             obj.tId = tId;
3005             if (isAbort) {
3006                 obj.status = ABORT_CODE;
3007                 obj.statusText = ABORT_ERROR;
3008             }
3009             else {
3010                 obj.status = COMM_CODE;
3011                 obj.statusText = COMM_ERROR;
3012             }
3013
3014             if (callbackArg) {
3015                 obj.argument = callbackArg;
3016             }
3017
3018             return obj;
3019         },
3020
3021         initHeader:function(label, value, isDefault)
3022         {
3023             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
3024
3025             if (headerObj[label] === undefined) {
3026                 headerObj[label] = value;
3027             }
3028             else {
3029
3030
3031                 headerObj[label] = value + "," + headerObj[label];
3032             }
3033
3034             if (isDefault) {
3035                 this.hasDefaultHeaders = true;
3036             }
3037             else {
3038                 this.hasHeaders = true;
3039             }
3040         },
3041
3042
3043         setHeader:function(o)
3044         {
3045             if (this.hasDefaultHeaders) {
3046                 for (var prop in this.defaultHeaders) {
3047                     if (this.defaultHeaders.hasOwnProperty(prop)) {
3048                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
3049                     }
3050                 }
3051             }
3052
3053             if (this.hasHeaders) {
3054                 for (var prop in this.headers) {
3055                     if (this.headers.hasOwnProperty(prop)) {
3056                         o.conn.setRequestHeader(prop, this.headers[prop]);
3057                     }
3058                 }
3059                 this.headers = {};
3060                 this.hasHeaders = false;
3061             }
3062         },
3063
3064         resetDefaultHeaders:function() {
3065             delete this.defaultHeaders;
3066             this.defaultHeaders = {};
3067             this.hasDefaultHeaders = false;
3068         },
3069
3070         abort:function(o, callback, isTimeout)
3071         {
3072             if(this.isCallInProgress(o)) {
3073                 o.conn.abort();
3074                 window.clearInterval(this.poll[o.tId]);
3075                 delete this.poll[o.tId];
3076                 if (isTimeout) {
3077                     delete this.timeout[o.tId];
3078                 }
3079
3080                 this.handleTransactionResponse(o, callback, true);
3081
3082                 return true;
3083             }
3084             else {
3085                 return false;
3086             }
3087         },
3088
3089
3090         isCallInProgress:function(o)
3091         {
3092             if (o && o.conn) {
3093                 return o.conn.readyState != 4 && o.conn.readyState != 0;
3094             }
3095             else {
3096
3097                 return false;
3098             }
3099         },
3100
3101
3102         releaseObject:function(o)
3103         {
3104
3105             o.conn = null;
3106
3107             o = null;
3108         },
3109
3110         activeX:[
3111         'MSXML2.XMLHTTP.3.0',
3112         'MSXML2.XMLHTTP',
3113         'Microsoft.XMLHTTP'
3114         ]
3115
3116
3117     };
3118 })();/*
3119  * Portions of this file are based on pieces of Yahoo User Interface Library
3120  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3121  * YUI licensed under the BSD License:
3122  * http://developer.yahoo.net/yui/license.txt
3123  * <script type="text/javascript">
3124  *
3125  */
3126
3127 Roo.lib.Region = function(t, r, b, l) {
3128     this.top = t;
3129     this[1] = t;
3130     this.right = r;
3131     this.bottom = b;
3132     this.left = l;
3133     this[0] = l;
3134 };
3135
3136
3137 Roo.lib.Region.prototype = {
3138     contains : function(region) {
3139         return ( region.left >= this.left &&
3140                  region.right <= this.right &&
3141                  region.top >= this.top &&
3142                  region.bottom <= this.bottom    );
3143
3144     },
3145
3146     getArea : function() {
3147         return ( (this.bottom - this.top) * (this.right - this.left) );
3148     },
3149
3150     intersect : function(region) {
3151         var t = Math.max(this.top, region.top);
3152         var r = Math.min(this.right, region.right);
3153         var b = Math.min(this.bottom, region.bottom);
3154         var l = Math.max(this.left, region.left);
3155
3156         if (b >= t && r >= l) {
3157             return new Roo.lib.Region(t, r, b, l);
3158         } else {
3159             return null;
3160         }
3161     },
3162     union : function(region) {
3163         var t = Math.min(this.top, region.top);
3164         var r = Math.max(this.right, region.right);
3165         var b = Math.max(this.bottom, region.bottom);
3166         var l = Math.min(this.left, region.left);
3167
3168         return new Roo.lib.Region(t, r, b, l);
3169     },
3170
3171     adjust : function(t, l, b, r) {
3172         this.top += t;
3173         this.left += l;
3174         this.right += r;
3175         this.bottom += b;
3176         return this;
3177     }
3178 };
3179
3180 Roo.lib.Region.getRegion = function(el) {
3181     var p = Roo.lib.Dom.getXY(el);
3182
3183     var t = p[1];
3184     var r = p[0] + el.offsetWidth;
3185     var b = p[1] + el.offsetHeight;
3186     var l = p[0];
3187
3188     return new Roo.lib.Region(t, r, b, l);
3189 };
3190 /*
3191  * Portions of this file are based on pieces of Yahoo User Interface Library
3192  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3193  * YUI licensed under the BSD License:
3194  * http://developer.yahoo.net/yui/license.txt
3195  * <script type="text/javascript">
3196  *
3197  */
3198 //@@dep Roo.lib.Region
3199
3200
3201 Roo.lib.Point = function(x, y) {
3202     if (x instanceof Array) {
3203         y = x[1];
3204         x = x[0];
3205     }
3206     this.x = this.right = this.left = this[0] = x;
3207     this.y = this.top = this.bottom = this[1] = y;
3208 };
3209
3210 Roo.lib.Point.prototype = new Roo.lib.Region();
3211 /*
3212  * Portions of this file are based on pieces of Yahoo User Interface Library
3213  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3214  * YUI licensed under the BSD License:
3215  * http://developer.yahoo.net/yui/license.txt
3216  * <script type="text/javascript">
3217  *
3218  */
3219  
3220 (function() {   
3221
3222     Roo.lib.Anim = {
3223         scroll : function(el, args, duration, easing, cb, scope) {
3224             this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3225         },
3226
3227         motion : function(el, args, duration, easing, cb, scope) {
3228             this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3229         },
3230
3231         color : function(el, args, duration, easing, cb, scope) {
3232             this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3233         },
3234
3235         run : function(el, args, duration, easing, cb, scope, type) {
3236             type = type || Roo.lib.AnimBase;
3237             if (typeof easing == "string") {
3238                 easing = Roo.lib.Easing[easing];
3239             }
3240             var anim = new type(el, args, duration, easing);
3241             anim.animateX(function() {
3242                 Roo.callback(cb, scope);
3243             });
3244             return anim;
3245         }
3246     };
3247 })();/*
3248  * Portions of this file are based on pieces of Yahoo User Interface Library
3249  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3250  * YUI licensed under the BSD License:
3251  * http://developer.yahoo.net/yui/license.txt
3252  * <script type="text/javascript">
3253  *
3254  */
3255
3256 (function() {    
3257     var libFlyweight;
3258     
3259     function fly(el) {
3260         if (!libFlyweight) {
3261             libFlyweight = new Roo.Element.Flyweight();
3262         }
3263         libFlyweight.dom = el;
3264         return libFlyweight;
3265     }
3266
3267     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3268     
3269    
3270     
3271     Roo.lib.AnimBase = function(el, attributes, duration, method) {
3272         if (el) {
3273             this.init(el, attributes, duration, method);
3274         }
3275     };
3276
3277     Roo.lib.AnimBase.fly = fly;
3278     
3279     
3280     
3281     Roo.lib.AnimBase.prototype = {
3282
3283         toString: function() {
3284             var el = this.getEl();
3285             var id = el.id || el.tagName;
3286             return ("Anim " + id);
3287         },
3288
3289         patterns: {
3290             noNegatives:        /width|height|opacity|padding/i,
3291             offsetAttribute:  /^((width|height)|(top|left))$/,
3292             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
3293             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3294         },
3295
3296
3297         doMethod: function(attr, start, end) {
3298             return this.method(this.currentFrame, start, end - start, this.totalFrames);
3299         },
3300
3301
3302         setAttribute: function(attr, val, unit) {
3303             if (this.patterns.noNegatives.test(attr)) {
3304                 val = (val > 0) ? val : 0;
3305             }
3306
3307             Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3308         },
3309
3310
3311         getAttribute: function(attr) {
3312             var el = this.getEl();
3313             var val = fly(el).getStyle(attr);
3314
3315             if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3316                 return parseFloat(val);
3317             }
3318
3319             var a = this.patterns.offsetAttribute.exec(attr) || [];
3320             var pos = !!( a[3] );
3321             var box = !!( a[2] );
3322
3323
3324             if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3325                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3326             } else {
3327                 val = 0;
3328             }
3329
3330             return val;
3331         },
3332
3333
3334         getDefaultUnit: function(attr) {
3335             if (this.patterns.defaultUnit.test(attr)) {
3336                 return 'px';
3337             }
3338
3339             return '';
3340         },
3341
3342         animateX : function(callback, scope) {
3343             var f = function() {
3344                 this.onComplete.removeListener(f);
3345                 if (typeof callback == "function") {
3346                     callback.call(scope || this, this);
3347                 }
3348             };
3349             this.onComplete.addListener(f, this);
3350             this.animate();
3351         },
3352
3353
3354         setRuntimeAttribute: function(attr) {
3355             var start;
3356             var end;
3357             var attributes = this.attributes;
3358
3359             this.runtimeAttributes[attr] = {};
3360
3361             var isset = function(prop) {
3362                 return (typeof prop !== 'undefined');
3363             };
3364
3365             if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3366                 return false;
3367             }
3368
3369             start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3370
3371
3372             if (isset(attributes[attr]['to'])) {
3373                 end = attributes[attr]['to'];
3374             } else if (isset(attributes[attr]['by'])) {
3375                 if (start.constructor == Array) {
3376                     end = [];
3377                     for (var i = 0, len = start.length; i < len; ++i) {
3378                         end[i] = start[i] + attributes[attr]['by'][i];
3379                     }
3380                 } else {
3381                     end = start + attributes[attr]['by'];
3382                 }
3383             }
3384
3385             this.runtimeAttributes[attr].start = start;
3386             this.runtimeAttributes[attr].end = end;
3387
3388
3389             this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3390         },
3391
3392
3393         init: function(el, attributes, duration, method) {
3394
3395             var isAnimated = false;
3396
3397
3398             var startTime = null;
3399
3400
3401             var actualFrames = 0;
3402
3403
3404             el = Roo.getDom(el);
3405
3406
3407             this.attributes = attributes || {};
3408
3409
3410             this.duration = duration || 1;
3411
3412
3413             this.method = method || Roo.lib.Easing.easeNone;
3414
3415
3416             this.useSeconds = true;
3417
3418
3419             this.currentFrame = 0;
3420
3421
3422             this.totalFrames = Roo.lib.AnimMgr.fps;
3423
3424
3425             this.getEl = function() {
3426                 return el;
3427             };
3428
3429
3430             this.isAnimated = function() {
3431                 return isAnimated;
3432             };
3433
3434
3435             this.getStartTime = function() {
3436                 return startTime;
3437             };
3438
3439             this.runtimeAttributes = {};
3440
3441
3442             this.animate = function() {
3443                 if (this.isAnimated()) {
3444                     return false;
3445                 }
3446
3447                 this.currentFrame = 0;
3448
3449                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3450
3451                 Roo.lib.AnimMgr.registerElement(this);
3452             };
3453
3454
3455             this.stop = function(finish) {
3456                 if (finish) {
3457                     this.currentFrame = this.totalFrames;
3458                     this._onTween.fire();
3459                 }
3460                 Roo.lib.AnimMgr.stop(this);
3461             };
3462
3463             var onStart = function() {
3464                 this.onStart.fire();
3465
3466                 this.runtimeAttributes = {};
3467                 for (var attr in this.attributes) {
3468                     this.setRuntimeAttribute(attr);
3469                 }
3470
3471                 isAnimated = true;
3472                 actualFrames = 0;
3473                 startTime = new Date();
3474             };
3475
3476
3477             var onTween = function() {
3478                 var data = {
3479                     duration: new Date() - this.getStartTime(),
3480                     currentFrame: this.currentFrame
3481                 };
3482
3483                 data.toString = function() {
3484                     return (
3485                             'duration: ' + data.duration +
3486                             ', currentFrame: ' + data.currentFrame
3487                             );
3488                 };
3489
3490                 this.onTween.fire(data);
3491
3492                 var runtimeAttributes = this.runtimeAttributes;
3493
3494                 for (var attr in runtimeAttributes) {
3495                     this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3496                 }
3497
3498                 actualFrames += 1;
3499             };
3500
3501             var onComplete = function() {
3502                 var actual_duration = (new Date() - startTime) / 1000 ;
3503
3504                 var data = {
3505                     duration: actual_duration,
3506                     frames: actualFrames,
3507                     fps: actualFrames / actual_duration
3508                 };
3509
3510                 data.toString = function() {
3511                     return (
3512                             'duration: ' + data.duration +
3513                             ', frames: ' + data.frames +
3514                             ', fps: ' + data.fps
3515                             );
3516                 };
3517
3518                 isAnimated = false;
3519                 actualFrames = 0;
3520                 this.onComplete.fire(data);
3521             };
3522
3523
3524             this._onStart = new Roo.util.Event(this);
3525             this.onStart = new Roo.util.Event(this);
3526             this.onTween = new Roo.util.Event(this);
3527             this._onTween = new Roo.util.Event(this);
3528             this.onComplete = new Roo.util.Event(this);
3529             this._onComplete = new Roo.util.Event(this);
3530             this._onStart.addListener(onStart);
3531             this._onTween.addListener(onTween);
3532             this._onComplete.addListener(onComplete);
3533         }
3534     };
3535 })();
3536 /*
3537  * Portions of this file are based on pieces of Yahoo User Interface Library
3538  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3539  * YUI licensed under the BSD License:
3540  * http://developer.yahoo.net/yui/license.txt
3541  * <script type="text/javascript">
3542  *
3543  */
3544
3545 Roo.lib.AnimMgr = new function() {
3546
3547     var thread = null;
3548
3549
3550     var queue = [];
3551
3552
3553     var tweenCount = 0;
3554
3555
3556     this.fps = 1000;
3557
3558
3559     this.delay = 1;
3560
3561
3562     this.registerElement = function(tween) {
3563         queue[queue.length] = tween;
3564         tweenCount += 1;
3565         tween._onStart.fire();
3566         this.start();
3567     };
3568
3569
3570     this.unRegister = function(tween, index) {
3571         tween._onComplete.fire();
3572         index = index || getIndex(tween);
3573         if (index != -1) {
3574             queue.splice(index, 1);
3575         }
3576
3577         tweenCount -= 1;
3578         if (tweenCount <= 0) {
3579             this.stop();
3580         }
3581     };
3582
3583
3584     this.start = function() {
3585         if (thread === null) {
3586             thread = setInterval(this.run, this.delay);
3587         }
3588     };
3589
3590
3591     this.stop = function(tween) {
3592         if (!tween) {
3593             clearInterval(thread);
3594
3595             for (var i = 0, len = queue.length; i < len; ++i) {
3596                 if (queue[0].isAnimated()) {
3597                     this.unRegister(queue[0], 0);
3598                 }
3599             }
3600
3601             queue = [];
3602             thread = null;
3603             tweenCount = 0;
3604         }
3605         else {
3606             this.unRegister(tween);
3607         }
3608     };
3609
3610
3611     this.run = function() {
3612         for (var i = 0, len = queue.length; i < len; ++i) {
3613             var tween = queue[i];
3614             if (!tween || !tween.isAnimated()) {
3615                 continue;
3616             }
3617
3618             if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3619             {
3620                 tween.currentFrame += 1;
3621
3622                 if (tween.useSeconds) {
3623                     correctFrame(tween);
3624                 }
3625                 tween._onTween.fire();
3626             }
3627             else {
3628                 Roo.lib.AnimMgr.stop(tween, i);
3629             }
3630         }
3631     };
3632
3633     var getIndex = function(anim) {
3634         for (var i = 0, len = queue.length; i < len; ++i) {
3635             if (queue[i] == anim) {
3636                 return i;
3637             }
3638         }
3639         return -1;
3640     };
3641
3642
3643     var correctFrame = function(tween) {
3644         var frames = tween.totalFrames;
3645         var frame = tween.currentFrame;
3646         var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3647         var elapsed = (new Date() - tween.getStartTime());
3648         var tweak = 0;
3649
3650         if (elapsed < tween.duration * 1000) {
3651             tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3652         } else {
3653             tweak = frames - (frame + 1);
3654         }
3655         if (tweak > 0 && isFinite(tweak)) {
3656             if (tween.currentFrame + tweak >= frames) {
3657                 tweak = frames - (frame + 1);
3658             }
3659
3660             tween.currentFrame += tweak;
3661         }
3662     };
3663 };
3664
3665     /*
3666  * Portions of this file are based on pieces of Yahoo User Interface Library
3667  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3668  * YUI licensed under the BSD License:
3669  * http://developer.yahoo.net/yui/license.txt
3670  * <script type="text/javascript">
3671  *
3672  */
3673 Roo.lib.Bezier = new function() {
3674
3675         this.getPosition = function(points, t) {
3676             var n = points.length;
3677             var tmp = [];
3678
3679             for (var i = 0; i < n; ++i) {
3680                 tmp[i] = [points[i][0], points[i][1]];
3681             }
3682
3683             for (var j = 1; j < n; ++j) {
3684                 for (i = 0; i < n - j; ++i) {
3685                     tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3686                     tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3687                 }
3688             }
3689
3690             return [ tmp[0][0], tmp[0][1] ];
3691
3692         };
3693     }; 
3694
3695 /**
3696  * @class Roo.lib.Color
3697  * @constructor
3698  * An abstract Color implementation. Concrete Color implementations should use
3699  * an instance of this function as their prototype, and implement the getRGB and
3700  * getHSL functions. getRGB should return an object representing the RGB
3701  * components of this Color, with the red, green, and blue components in the
3702  * range [0,255] and the alpha component in the range [0,100]. getHSL should
3703  * return an object representing the HSL components of this Color, with the hue
3704  * component in the range [0,360), the saturation and lightness components in
3705  * the range [0,100], and the alpha component in the range [0,1].
3706  *
3707  *
3708  * Color.js
3709  *
3710  * Functions for Color handling and processing.
3711  *
3712  * http://www.safalra.com/web-design/javascript/Color-handling-and-processing/
3713  *
3714  * The author of this program, Safalra (Stephen Morley), irrevocably releases all
3715  * rights to this program, with the intention of it becoming part of the public
3716  * domain. Because this program is released into the public domain, it comes with
3717  * no warranty either expressed or implied, to the extent permitted by law.
3718  * 
3719  * For more free and public domain JavaScript code by the same author, visit:
3720  * http://www.safalra.com/web-design/javascript/
3721  * 
3722  */
3723 Roo.lib.Color = function() { }
3724
3725
3726 Roo.apply(Roo.lib.Color.prototype, {
3727   
3728   rgb : null,
3729   hsv : null,
3730   hsl : null,
3731   
3732   /**
3733    * getIntegerRGB
3734    * @return {Object} an object representing the RGBA components of this Color. The red,
3735    * green, and blue components are converted to integers in the range [0,255].
3736    * The alpha is a value in the range [0,1].
3737    */
3738   getIntegerRGB : function(){
3739
3740     // get the RGB components of this Color
3741     var rgb = this.getRGB();
3742
3743     // return the integer components
3744     return {
3745       'r' : Math.round(rgb.r),
3746       'g' : Math.round(rgb.g),
3747       'b' : Math.round(rgb.b),
3748       'a' : rgb.a
3749     };
3750
3751   },
3752
3753   /**
3754    * getPercentageRGB
3755    * @return {Object} an object representing the RGBA components of this Color. The red,
3756    * green, and blue components are converted to numbers in the range [0,100].
3757    * The alpha is a value in the range [0,1].
3758    */
3759   getPercentageRGB : function(){
3760
3761     // get the RGB components of this Color
3762     var rgb = this.getRGB();
3763
3764     // return the percentage components
3765     return {
3766       'r' : 100 * rgb.r / 255,
3767       'g' : 100 * rgb.g / 255,
3768       'b' : 100 * rgb.b / 255,
3769       'a' : rgb.a
3770     };
3771
3772   },
3773
3774   /**
3775    * getCSSHexadecimalRGB
3776    * @return {String} a string representing this Color as a CSS hexadecimal RGB Color
3777    * value - that is, a string of the form #RRGGBB where each of RR, GG, and BB
3778    * are two-digit hexadecimal numbers.
3779    */
3780   getCSSHexadecimalRGB : function()
3781   {
3782
3783     // get the integer RGB components
3784     var rgb = this.getIntegerRGB();
3785
3786     // determine the hexadecimal equivalents
3787     var r16 = rgb.r.toString(16);
3788     var g16 = rgb.g.toString(16);
3789     var b16 = rgb.b.toString(16);
3790
3791     // return the CSS RGB Color value
3792     return '#'
3793         + (r16.length == 2 ? r16 : '0' + r16)
3794         + (g16.length == 2 ? g16 : '0' + g16)
3795         + (b16.length == 2 ? b16 : '0' + b16);
3796
3797   },
3798
3799   /**
3800    * getCSSIntegerRGB
3801    * @return {String} a string representing this Color as a CSS integer RGB Color
3802    * value - that is, a string of the form rgb(r,g,b) where each of r, g, and b
3803    * are integers in the range [0,255].
3804    */
3805   getCSSIntegerRGB : function(){
3806
3807     // get the integer RGB components
3808     var rgb = this.getIntegerRGB();
3809
3810     // return the CSS RGB Color value
3811     return 'rgb(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ')';
3812
3813   },
3814
3815   /**
3816    * getCSSIntegerRGBA
3817    * @return {String} Returns a string representing this Color as a CSS integer RGBA Color
3818    * value - that is, a string of the form rgba(r,g,b,a) where each of r, g, and
3819    * b are integers in the range [0,255] and a is in the range [0,1].
3820    */
3821   getCSSIntegerRGBA : function(){
3822
3823     // get the integer RGB components
3824     var rgb = this.getIntegerRGB();
3825
3826     // return the CSS integer RGBA Color value
3827     return 'rgb(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ',' + rgb.a + ')';
3828
3829   },
3830
3831   /**
3832    * getCSSPercentageRGB
3833    * @return {String} a string representing this Color as a CSS percentage RGB Color
3834    * value - that is, a string of the form rgb(r%,g%,b%) where each of r, g, and
3835    * b are in the range [0,100].
3836    */
3837   getCSSPercentageRGB : function(){
3838
3839     // get the percentage RGB components
3840     var rgb = this.getPercentageRGB();
3841
3842     // return the CSS RGB Color value
3843     return 'rgb(' + rgb.r + '%,' + rgb.g + '%,' + rgb.b + '%)';
3844
3845   },
3846
3847   /**
3848    * getCSSPercentageRGBA
3849    * @return {String} a string representing this Color as a CSS percentage RGBA Color
3850    * value - that is, a string of the form rgba(r%,g%,b%,a) where each of r, g,
3851    * and b are in the range [0,100] and a is in the range [0,1].
3852    */
3853   getCSSPercentageRGBA : function(){
3854
3855     // get the percentage RGB components
3856     var rgb = this.getPercentageRGB();
3857
3858     // return the CSS percentage RGBA Color value
3859     return 'rgb(' + rgb.r + '%,' + rgb.g + '%,' + rgb.b + '%,' + rgb.a + ')';
3860
3861   },
3862
3863   /**
3864    * getCSSHSL
3865    * @return {String} a string representing this Color as a CSS HSL Color value - that
3866    * is, a string of the form hsl(h,s%,l%) where h is in the range [0,100] and
3867    * s and l are in the range [0,100].
3868    */
3869   getCSSHSL : function(){
3870
3871     // get the HSL components
3872     var hsl = this.getHSL();
3873
3874     // return the CSS HSL Color value
3875     return 'hsl(' + hsl.h + ',' + hsl.s + '%,' + hsl.l + '%)';
3876
3877   },
3878
3879   /**
3880    * getCSSHSLA
3881    * @return {String} a string representing this Color as a CSS HSLA Color value - that
3882    * is, a string of the form hsla(h,s%,l%,a) where h is in the range [0,100],
3883    * s and l are in the range [0,100], and a is in the range [0,1].
3884    */
3885   getCSSHSLA : function(){
3886
3887     // get the HSL components
3888     var hsl = this.getHSL();
3889
3890     // return the CSS HSL Color value
3891     return 'hsl(' + hsl.h + ',' + hsl.s + '%,' + hsl.l + '%,' + hsl.a + ')';
3892
3893   },
3894
3895   /**
3896    * Sets the Color of the specified node to this Color. This functions sets
3897    * the CSS 'color' property for the node. The parameter is:
3898    * 
3899    * @param {DomElement} node - the node whose Color should be set
3900    */
3901   setNodeColor : function(node){
3902
3903     // set the Color of the node
3904     node.style.color = this.getCSSHexadecimalRGB();
3905
3906   },
3907
3908   /**
3909    * Sets the background Color of the specified node to this Color. This
3910    * functions sets the CSS 'background-color' property for the node. The
3911    * parameter is:
3912    *
3913    * @param {DomElement} node - the node whose background Color should be set
3914    */
3915   setNodeBackgroundColor : function(node){
3916
3917     // set the background Color of the node
3918     node.style.backgroundColor = this.getCSSHexadecimalRGB();
3919
3920   },
3921   // convert between formats..
3922   toRGB: function()
3923   {
3924     var r = this.getIntegerRGB();
3925     return new Roo.lib.RGBColor(r.r,r.g,r.b,r.a);
3926     
3927   },
3928   toHSL : function()
3929   {
3930      var hsl = this.getHSL();
3931   // return the CSS HSL Color value
3932     return new Roo.lib.HSLColor(hsl.h,  hsl.s, hsl.l ,  hsl.a );
3933     
3934   },
3935   
3936   toHSV : function()
3937   {
3938     var rgb = this.toRGB();
3939     var hsv = rgb.getHSV();
3940    // return the CSS HSL Color value
3941     return new Roo.lib.HSVColor(hsv.h,  hsv.s, hsv.v ,  hsv.a );
3942     
3943   },
3944   
3945   // modify  v = 0 ... 1 (eg. 0.5)
3946   saturate : function(v)
3947   {
3948       var rgb = this.toRGB();
3949       var hsv = rgb.getHSV();
3950       return new Roo.lib.HSVColor(hsv.h,  hsv.s * v, hsv.v ,  hsv.a );
3951       
3952   
3953   },
3954   
3955    
3956   /**
3957    * getRGB
3958    * @return {Object} the RGB and alpha components of this Color as an object with r,
3959    * g, b, and a properties. r, g, and b are in the range [0,255] and a is in
3960    * the range [0,1].
3961    */
3962   getRGB: function(){
3963    
3964     // return the RGB components
3965     return {
3966       'r' : this.rgb.r,
3967       'g' : this.rgb.g,
3968       'b' : this.rgb.b,
3969       'a' : this.alpha
3970     };
3971
3972   },
3973
3974   /**
3975    * getHSV
3976    * @return {Object} the HSV and alpha components of this Color as an object with h,
3977    * s, v, and a properties. h is in the range [0,360), s and v are in the range
3978    * [0,100], and a is in the range [0,1].
3979    */
3980   getHSV : function()
3981   {
3982     
3983     // calculate the HSV components if necessary
3984     if (this.hsv == null) {
3985       this.calculateHSV();
3986     }
3987
3988     // return the HSV components
3989     return {
3990       'h' : this.hsv.h,
3991       's' : this.hsv.s,
3992       'v' : this.hsv.v,
3993       'a' : this.alpha
3994     };
3995
3996   },
3997
3998   /**
3999    * getHSL
4000    * @return {Object} the HSL and alpha components of this Color as an object with h,
4001    * s, l, and a properties. h is in the range [0,360), s and l are in the range
4002    * [0,100], and a is in the range [0,1].
4003    */
4004   getHSL : function(){
4005     
4006      
4007     // calculate the HSV components if necessary
4008     if (this.hsl == null) { this.calculateHSL(); }
4009
4010     // return the HSL components
4011     return {
4012       'h' : this.hsl.h,
4013       's' : this.hsl.s,
4014       'l' : this.hsl.l,
4015       'a' : this.alpha
4016     };
4017
4018   }
4019   
4020
4021 });
4022
4023
4024 /**
4025  * @class Roo.lib.RGBColor
4026  * @extends Roo.lib.Color
4027  * Creates a Color specified in the RGB Color space, with an optional alpha
4028  * component. The parameters are:
4029  * @constructor
4030  * 
4031
4032  * @param {Number} r - the red component, clipped to the range [0,255]
4033  * @param {Number} g - the green component, clipped to the range [0,255]
4034  * @param {Number} b - the blue component, clipped to the range [0,255]
4035  * @param {Number} a - the alpha component, clipped to the range [0,1] - this parameter is
4036  *     optional and defaults to 1
4037  */
4038 Roo.lib.RGBColor = function (r, g, b, a){
4039
4040   // store the alpha component after clipping it if necessary
4041   this.alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
4042
4043   // store the RGB components after clipping them if necessary
4044   this.rgb =
4045       {
4046         'r' : Math.max(0, Math.min(255, r)),
4047         'g' : Math.max(0, Math.min(255, g)),
4048         'b' : Math.max(0, Math.min(255, b))
4049       };
4050
4051   // initialise the HSV and HSL components to null
4052   
4053
4054   /* 
4055    * //private returns the HSV or HSL hue component of this RGBColor. The hue is in the
4056    * range [0,360). The parameters are:
4057    *
4058    * maximum - the maximum of the RGB component values
4059    * range   - the range of the RGB component values
4060    */
4061    
4062
4063 }
4064 // this does an 'exteds'
4065 Roo.extend(Roo.lib.RGBColor, Roo.lib.Color, {
4066
4067   
4068     getHue  : function(maximum, range)
4069     {
4070       var rgb = this.rgb;
4071        
4072       // check whether the range is zero
4073       if (range == 0){
4074   
4075         // set the hue to zero (any hue is acceptable as the Color is grey)
4076         var hue = 0;
4077   
4078       }else{
4079   
4080         // determine which of the components has the highest value and set the hue
4081         switch (maximum){
4082   
4083           // red has the highest value
4084           case rgb.r:
4085             var hue = (rgb.g - rgb.b) / range * 60;
4086             if (hue < 0) { hue += 360; }
4087             break;
4088   
4089           // green has the highest value
4090           case rgb.g:
4091             var hue = (rgb.b - rgb.r) / range * 60 + 120;
4092             break;
4093   
4094           // blue has the highest value
4095           case rgb.b:
4096             var hue = (rgb.r - rgb.g) / range * 60 + 240;
4097             break;
4098   
4099         }
4100   
4101       }
4102   
4103       // return the hue
4104       return hue;
4105   
4106     },
4107
4108   /* //private Calculates and stores the HSV components of this RGBColor so that they can
4109    * be returned be the getHSV function.
4110    */
4111    calculateHSV : function(){
4112     var rgb = this.rgb;
4113     // get the maximum and range of the RGB component values
4114     var maximum = Math.max(rgb.r, rgb.g, rgb.b);
4115     var range   = maximum - Math.min(rgb.r, rgb.g, rgb.b);
4116
4117     // store the HSV components
4118     this.hsv =
4119         {
4120           'h' : this.getHue(maximum, range),
4121           's' : (maximum == 0 ? 0 : 100 * range / maximum),
4122           'v' : maximum / 2.55
4123         };
4124
4125   },
4126
4127   /* //private Calculates and stores the HSL components of this RGBColor so that they can
4128    * be returned be the getHSL function.
4129    */
4130    calculateHSL : function(){
4131     var rgb = this.rgb;
4132     // get the maximum and range of the RGB component values
4133     var maximum = Math.max(rgb.r, rgb.g, rgb.b);
4134     var range   = maximum - Math.min(rgb.r, rgb.g, rgb.b);
4135
4136     // determine the lightness in the range [0,1]
4137     var l = maximum / 255 - range / 510;
4138
4139     // store the HSL components
4140     this.hsl =
4141         {
4142           'h' : this.getHue(maximum, range),
4143           's' : (range == 0 ? 0 : range / 2.55 / (l < 0.5 ? l * 2 : 2 - l * 2)),
4144           'l' : 100 * l
4145         };
4146
4147   }
4148
4149 });
4150
4151 /**
4152  * @class Roo.lib.HSVColor
4153  * @extends Roo.lib.Color
4154  * Creates a Color specified in the HSV Color space, with an optional alpha
4155  * component. The parameters are:
4156  * @constructor
4157  *
4158  * @param {Number} h - the hue component, wrapped to the range [0,360)
4159  * @param {Number} s - the saturation component, clipped to the range [0,100]
4160  * @param {Number} v - the value component, clipped to the range [0,100]
4161  * @param {Number} a - the alpha component, clipped to the range [0,1] - this parameter is
4162  *     optional and defaults to 1
4163  */
4164 Roo.lib.HSVColor = function (h, s, v, a){
4165
4166   // store the alpha component after clipping it if necessary
4167   this.alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
4168
4169   // store the HSV components after clipping or wrapping them if necessary
4170   this.hsv =
4171       {
4172         'h' : (h % 360 + 360) % 360,
4173         's' : Math.max(0, Math.min(100, s)),
4174         'v' : Math.max(0, Math.min(100, v))
4175       };
4176
4177   // initialise the RGB and HSL components to null
4178   this.rgb = null;
4179   this.hsl = null;
4180 }
4181
4182 Roo.extend(Roo.lib.HSVColor, Roo.lib.Color, {
4183   /* Calculates and stores the RGB components of this HSVColor so that they can
4184    * be returned be the getRGB function.
4185    */
4186   calculateRGB: function ()
4187   {
4188     var hsv = this.hsv;
4189     // check whether the saturation is zero
4190     if (hsv.s == 0){
4191
4192       // set the Color to the appropriate shade of grey
4193       var r = hsv.v;
4194       var g = hsv.v;
4195       var b = hsv.v;
4196
4197     }else{
4198
4199       // set some temporary values
4200       var f  = hsv.h / 60 - Math.floor(hsv.h / 60);
4201       var p  = hsv.v * (1 - hsv.s / 100);
4202       var q  = hsv.v * (1 - hsv.s / 100 * f);
4203       var t  = hsv.v * (1 - hsv.s / 100 * (1 - f));
4204
4205       // set the RGB Color components to their temporary values
4206       switch (Math.floor(hsv.h / 60)){
4207         case 0: var r = hsv.v; var g = t; var b = p; break;
4208         case 1: var r = q; var g = hsv.v; var b = p; break;
4209         case 2: var r = p; var g = hsv.v; var b = t; break;
4210         case 3: var r = p; var g = q; var b = hsv.v; break;
4211         case 4: var r = t; var g = p; var b = hsv.v; break;
4212         case 5: var r = hsv.v; var g = p; var b = q; break;
4213       }
4214
4215     }
4216
4217     // store the RGB components
4218     this.rgb =
4219         {
4220           'r' : r * 2.55,
4221           'g' : g * 2.55,
4222           'b' : b * 2.55
4223         };
4224
4225   },
4226
4227   /* Calculates and stores the HSL components of this HSVColor so that they can
4228    * be returned be the getHSL function.
4229    */
4230   calculateHSL : function (){
4231
4232     var hsv = this.hsv;
4233     // determine the lightness in the range [0,100]
4234     var l = (2 - hsv.s / 100) * hsv.v / 2;
4235
4236     // store the HSL components
4237     this.hsl =
4238         {
4239           'h' : hsv.h,
4240           's' : hsv.s * hsv.v / (l < 50 ? l * 2 : 200 - l * 2),
4241           'l' : l
4242         };
4243
4244     // correct a division-by-zero error
4245     if (isNaN(hsl.s)) { hsl.s = 0; }
4246
4247   } 
4248  
4249
4250 });
4251  
4252
4253 /**
4254  * @class Roo.lib.HSLColor
4255  * @extends Roo.lib.Color
4256  *
4257  * @constructor
4258  * Creates a Color specified in the HSL Color space, with an optional alpha
4259  * component. The parameters are:
4260  *
4261  * @param {Number} h - the hue component, wrapped to the range [0,360)
4262  * @param {Number} s - the saturation component, clipped to the range [0,100]
4263  * @param {Number} l - the lightness component, clipped to the range [0,100]
4264  * @param {Number} a - the alpha component, clipped to the range [0,1] - this parameter is
4265  *     optional and defaults to 1
4266  */
4267
4268 Roo.lib.HSLColor = function(h, s, l, a){
4269
4270   // store the alpha component after clipping it if necessary
4271   this.alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
4272
4273   // store the HSL components after clipping or wrapping them if necessary
4274   this.hsl =
4275       {
4276         'h' : (h % 360 + 360) % 360,
4277         's' : Math.max(0, Math.min(100, s)),
4278         'l' : Math.max(0, Math.min(100, l))
4279       };
4280
4281   // initialise the RGB and HSV components to null
4282 }
4283
4284 Roo.extend(Roo.lib.HSLColor, Roo.lib.Color, {
4285
4286   /* Calculates and stores the RGB components of this HSLColor so that they can
4287    * be returned be the getRGB function.
4288    */
4289   calculateRGB: function (){
4290
4291     // check whether the saturation is zero
4292     if (this.hsl.s == 0){
4293
4294       // store the RGB components representing the appropriate shade of grey
4295       this.rgb =
4296           {
4297             'r' : this.hsl.l * 2.55,
4298             'g' : this.hsl.l * 2.55,
4299             'b' : this.hsl.l * 2.55
4300           };
4301
4302     }else{
4303
4304       // set some temporary values
4305       var p = this.hsl.l < 50
4306             ? this.hsl.l * (1 + hsl.s / 100)
4307             : this.hsl.l + hsl.s - hsl.l * hsl.s / 100;
4308       var q = 2 * hsl.l - p;
4309
4310       // initialise the RGB components
4311       this.rgb =
4312           {
4313             'r' : (h + 120) / 60 % 6,
4314             'g' : h / 60,
4315             'b' : (h + 240) / 60 % 6
4316           };
4317
4318       // loop over the RGB components
4319       for (var key in this.rgb){
4320
4321         // ensure that the property is not inherited from the root object
4322         if (this.rgb.hasOwnProperty(key)){
4323
4324           // set the component to its value in the range [0,100]
4325           if (this.rgb[key] < 1){
4326             this.rgb[key] = q + (p - q) * this.rgb[key];
4327           }else if (this.rgb[key] < 3){
4328             this.rgb[key] = p;
4329           }else if (this.rgb[key] < 4){
4330             this.rgb[key] = q + (p - q) * (4 - this.rgb[key]);
4331           }else{
4332             this.rgb[key] = q;
4333           }
4334
4335           // set the component to its value in the range [0,255]
4336           this.rgb[key] *= 2.55;
4337
4338         }
4339
4340       }
4341
4342     }
4343
4344   },
4345
4346   /* Calculates and stores the HSV components of this HSLColor so that they can
4347    * be returned be the getHSL function.
4348    */
4349    calculateHSV : function(){
4350
4351     // set a temporary value
4352     var t = this.hsl.s * (this.hsl.l < 50 ? this.hsl.l : 100 - this.hsl.l) / 100;
4353
4354     // store the HSV components
4355     this.hsv =
4356         {
4357           'h' : this.hsl.h,
4358           's' : 200 * t / (this.hsl.l + t),
4359           'v' : t + this.hsl.l
4360         };
4361
4362     // correct a division-by-zero error
4363     if (isNaN(this.hsv.s)) { this.hsv.s = 0; }
4364
4365   }
4366  
4367
4368 });
4369 /*
4370  * Portions of this file are based on pieces of Yahoo User Interface Library
4371  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4372  * YUI licensed under the BSD License:
4373  * http://developer.yahoo.net/yui/license.txt
4374  * <script type="text/javascript">
4375  *
4376  */
4377 (function() {
4378
4379     Roo.lib.ColorAnim = function(el, attributes, duration, method) {
4380         Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
4381     };
4382
4383     Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
4384
4385     var fly = Roo.lib.AnimBase.fly;
4386     var Y = Roo.lib;
4387     var superclass = Y.ColorAnim.superclass;
4388     var proto = Y.ColorAnim.prototype;
4389
4390     proto.toString = function() {
4391         var el = this.getEl();
4392         var id = el.id || el.tagName;
4393         return ("ColorAnim " + id);
4394     };
4395
4396     proto.patterns.color = /color$/i;
4397     proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
4398     proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
4399     proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
4400     proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
4401
4402
4403     proto.parseColor = function(s) {
4404         if (s.length == 3) {
4405             return s;
4406         }
4407
4408         var c = this.patterns.hex.exec(s);
4409         if (c && c.length == 4) {
4410             return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
4411         }
4412
4413         c = this.patterns.rgb.exec(s);
4414         if (c && c.length == 4) {
4415             return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
4416         }
4417
4418         c = this.patterns.hex3.exec(s);
4419         if (c && c.length == 4) {
4420             return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
4421         }
4422
4423         return null;
4424     };
4425     // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
4426     proto.getAttribute = function(attr) {
4427         var el = this.getEl();
4428         if (this.patterns.color.test(attr)) {
4429             var val = fly(el).getStyle(attr);
4430
4431             if (this.patterns.transparent.test(val)) {
4432                 var parent = el.parentNode;
4433                 val = fly(parent).getStyle(attr);
4434
4435                 while (parent && this.patterns.transparent.test(val)) {
4436                     parent = parent.parentNode;
4437                     val = fly(parent).getStyle(attr);
4438                     if (parent.tagName.toUpperCase() == 'HTML') {
4439                         val = '#fff';
4440                     }
4441                 }
4442             }
4443         } else {
4444             val = superclass.getAttribute.call(this, attr);
4445         }
4446
4447         return val;
4448     };
4449     proto.getAttribute = function(attr) {
4450         var el = this.getEl();
4451         if (this.patterns.color.test(attr)) {
4452             var val = fly(el).getStyle(attr);
4453
4454             if (this.patterns.transparent.test(val)) {
4455                 var parent = el.parentNode;
4456                 val = fly(parent).getStyle(attr);
4457
4458                 while (parent && this.patterns.transparent.test(val)) {
4459                     parent = parent.parentNode;
4460                     val = fly(parent).getStyle(attr);
4461                     if (parent.tagName.toUpperCase() == 'HTML') {
4462                         val = '#fff';
4463                     }
4464                 }
4465             }
4466         } else {
4467             val = superclass.getAttribute.call(this, attr);
4468         }
4469
4470         return val;
4471     };
4472
4473     proto.doMethod = function(attr, start, end) {
4474         var val;
4475
4476         if (this.patterns.color.test(attr)) {
4477             val = [];
4478             for (var i = 0, len = start.length; i < len; ++i) {
4479                 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
4480             }
4481
4482             val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
4483         }
4484         else {
4485             val = superclass.doMethod.call(this, attr, start, end);
4486         }
4487
4488         return val;
4489     };
4490
4491     proto.setRuntimeAttribute = function(attr) {
4492         superclass.setRuntimeAttribute.call(this, attr);
4493
4494         if (this.patterns.color.test(attr)) {
4495             var attributes = this.attributes;
4496             var start = this.parseColor(this.runtimeAttributes[attr].start);
4497             var end = this.parseColor(this.runtimeAttributes[attr].end);
4498
4499             if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
4500                 end = this.parseColor(attributes[attr].by);
4501
4502                 for (var i = 0, len = start.length; i < len; ++i) {
4503                     end[i] = start[i] + end[i];
4504                 }
4505             }
4506
4507             this.runtimeAttributes[attr].start = start;
4508             this.runtimeAttributes[attr].end = end;
4509         }
4510     };
4511 })();
4512
4513 /*
4514  * Portions of this file are based on pieces of Yahoo User Interface Library
4515  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4516  * YUI licensed under the BSD License:
4517  * http://developer.yahoo.net/yui/license.txt
4518  * <script type="text/javascript">
4519  *
4520  */
4521 Roo.lib.Easing = {
4522
4523
4524     easeNone: function (t, b, c, d) {
4525         return c * t / d + b;
4526     },
4527
4528
4529     easeIn: function (t, b, c, d) {
4530         return c * (t /= d) * t + b;
4531     },
4532
4533
4534     easeOut: function (t, b, c, d) {
4535         return -c * (t /= d) * (t - 2) + b;
4536     },
4537
4538
4539     easeBoth: function (t, b, c, d) {
4540         if ((t /= d / 2) < 1) {
4541             return c / 2 * t * t + b;
4542         }
4543
4544         return -c / 2 * ((--t) * (t - 2) - 1) + b;
4545     },
4546
4547
4548     easeInStrong: function (t, b, c, d) {
4549         return c * (t /= d) * t * t * t + b;
4550     },
4551
4552
4553     easeOutStrong: function (t, b, c, d) {
4554         return -c * ((t = t / d - 1) * t * t * t - 1) + b;
4555     },
4556
4557
4558     easeBothStrong: function (t, b, c, d) {
4559         if ((t /= d / 2) < 1) {
4560             return c / 2 * t * t * t * t + b;
4561         }
4562
4563         return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
4564     },
4565
4566
4567
4568     elasticIn: function (t, b, c, d, a, p) {
4569         if (t == 0) {
4570             return b;
4571         }
4572         if ((t /= d) == 1) {
4573             return b + c;
4574         }
4575         if (!p) {
4576             p = d * .3;
4577         }
4578
4579         if (!a || a < Math.abs(c)) {
4580             a = c;
4581             var s = p / 4;
4582         }
4583         else {
4584             var s = p / (2 * Math.PI) * Math.asin(c / a);
4585         }
4586
4587         return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
4588     },
4589
4590
4591     elasticOut: function (t, b, c, d, a, p) {
4592         if (t == 0) {
4593             return b;
4594         }
4595         if ((t /= d) == 1) {
4596             return b + c;
4597         }
4598         if (!p) {
4599             p = d * .3;
4600         }
4601
4602         if (!a || a < Math.abs(c)) {
4603             a = c;
4604             var s = p / 4;
4605         }
4606         else {
4607             var s = p / (2 * Math.PI) * Math.asin(c / a);
4608         }
4609
4610         return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
4611     },
4612
4613
4614     elasticBoth: function (t, b, c, d, a, p) {
4615         if (t == 0) {
4616             return b;
4617         }
4618
4619         if ((t /= d / 2) == 2) {
4620             return b + c;
4621         }
4622
4623         if (!p) {
4624             p = d * (.3 * 1.5);
4625         }
4626
4627         if (!a || a < Math.abs(c)) {
4628             a = c;
4629             var s = p / 4;
4630         }
4631         else {
4632             var s = p / (2 * Math.PI) * Math.asin(c / a);
4633         }
4634
4635         if (t < 1) {
4636             return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
4637                           Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
4638         }
4639         return a * Math.pow(2, -10 * (t -= 1)) *
4640                Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
4641     },
4642
4643
4644
4645     backIn: function (t, b, c, d, s) {
4646         if (typeof s == 'undefined') {
4647             s = 1.70158;
4648         }
4649         return c * (t /= d) * t * ((s + 1) * t - s) + b;
4650     },
4651
4652
4653     backOut: function (t, b, c, d, s) {
4654         if (typeof s == 'undefined') {
4655             s = 1.70158;
4656         }
4657         return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
4658     },
4659
4660
4661     backBoth: function (t, b, c, d, s) {
4662         if (typeof s == 'undefined') {
4663             s = 1.70158;
4664         }
4665
4666         if ((t /= d / 2 ) < 1) {
4667             return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
4668         }
4669         return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
4670     },
4671
4672
4673     bounceIn: function (t, b, c, d) {
4674         return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
4675     },
4676
4677
4678     bounceOut: function (t, b, c, d) {
4679         if ((t /= d) < (1 / 2.75)) {
4680             return c * (7.5625 * t * t) + b;
4681         } else if (t < (2 / 2.75)) {
4682             return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
4683         } else if (t < (2.5 / 2.75)) {
4684             return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
4685         }
4686         return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
4687     },
4688
4689
4690     bounceBoth: function (t, b, c, d) {
4691         if (t < d / 2) {
4692             return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
4693         }
4694         return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
4695     }
4696 };/*
4697  * Portions of this file are based on pieces of Yahoo User Interface Library
4698  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4699  * YUI licensed under the BSD License:
4700  * http://developer.yahoo.net/yui/license.txt
4701  * <script type="text/javascript">
4702  *
4703  */
4704     (function() {
4705         Roo.lib.Motion = function(el, attributes, duration, method) {
4706             if (el) {
4707                 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
4708             }
4709         };
4710
4711         Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
4712
4713
4714         var Y = Roo.lib;
4715         var superclass = Y.Motion.superclass;
4716         var proto = Y.Motion.prototype;
4717
4718         proto.toString = function() {
4719             var el = this.getEl();
4720             var id = el.id || el.tagName;
4721             return ("Motion " + id);
4722         };
4723
4724         proto.patterns.points = /^points$/i;
4725
4726         proto.setAttribute = function(attr, val, unit) {
4727             if (this.patterns.points.test(attr)) {
4728                 unit = unit || 'px';
4729                 superclass.setAttribute.call(this, 'left', val[0], unit);
4730                 superclass.setAttribute.call(this, 'top', val[1], unit);
4731             } else {
4732                 superclass.setAttribute.call(this, attr, val, unit);
4733             }
4734         };
4735
4736         proto.getAttribute = function(attr) {
4737             if (this.patterns.points.test(attr)) {
4738                 var val = [
4739                         superclass.getAttribute.call(this, 'left'),
4740                         superclass.getAttribute.call(this, 'top')
4741                         ];
4742             } else {
4743                 val = superclass.getAttribute.call(this, attr);
4744             }
4745
4746             return val;
4747         };
4748
4749         proto.doMethod = function(attr, start, end) {
4750             var val = null;
4751
4752             if (this.patterns.points.test(attr)) {
4753                 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
4754                 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
4755             } else {
4756                 val = superclass.doMethod.call(this, attr, start, end);
4757             }
4758             return val;
4759         };
4760
4761         proto.setRuntimeAttribute = function(attr) {
4762             if (this.patterns.points.test(attr)) {
4763                 var el = this.getEl();
4764                 var attributes = this.attributes;
4765                 var start;
4766                 var control = attributes['points']['control'] || [];
4767                 var end;
4768                 var i, len;
4769
4770                 if (control.length > 0 && !(control[0] instanceof Array)) {
4771                     control = [control];
4772                 } else {
4773                     var tmp = [];
4774                     for (i = 0,len = control.length; i < len; ++i) {
4775                         tmp[i] = control[i];
4776                     }
4777                     control = tmp;
4778                 }
4779
4780                 Roo.fly(el).position();
4781
4782                 if (isset(attributes['points']['from'])) {
4783                     Roo.lib.Dom.setXY(el, attributes['points']['from']);
4784                 }
4785                 else {
4786                     Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
4787                 }
4788
4789                 start = this.getAttribute('points');
4790
4791
4792                 if (isset(attributes['points']['to'])) {
4793                     end = translateValues.call(this, attributes['points']['to'], start);
4794
4795                     var pageXY = Roo.lib.Dom.getXY(this.getEl());
4796                     for (i = 0,len = control.length; i < len; ++i) {
4797                         control[i] = translateValues.call(this, control[i], start);
4798                     }
4799
4800
4801                 } else if (isset(attributes['points']['by'])) {
4802                     end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4803
4804                     for (i = 0,len = control.length; i < len; ++i) {
4805                         control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4806                     }
4807                 }
4808
4809                 this.runtimeAttributes[attr] = [start];
4810
4811                 if (control.length > 0) {
4812                     this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4813                 }
4814
4815                 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4816             }
4817             else {
4818                 superclass.setRuntimeAttribute.call(this, attr);
4819             }
4820         };
4821
4822         var translateValues = function(val, start) {
4823             var pageXY = Roo.lib.Dom.getXY(this.getEl());
4824             val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4825
4826             return val;
4827         };
4828
4829         var isset = function(prop) {
4830             return (typeof prop !== 'undefined');
4831         };
4832     })();
4833 /*
4834  * Portions of this file are based on pieces of Yahoo User Interface Library
4835  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4836  * YUI licensed under the BSD License:
4837  * http://developer.yahoo.net/yui/license.txt
4838  * <script type="text/javascript">
4839  *
4840  */
4841     (function() {
4842         Roo.lib.Scroll = function(el, attributes, duration, method) {
4843             if (el) {
4844                 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4845             }
4846         };
4847
4848         Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4849
4850
4851         var Y = Roo.lib;
4852         var superclass = Y.Scroll.superclass;
4853         var proto = Y.Scroll.prototype;
4854
4855         proto.toString = function() {
4856             var el = this.getEl();
4857             var id = el.id || el.tagName;
4858             return ("Scroll " + id);
4859         };
4860
4861         proto.doMethod = function(attr, start, end) {
4862             var val = null;
4863
4864             if (attr == 'scroll') {
4865                 val = [
4866                         this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4867                         this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4868                         ];
4869
4870             } else {
4871                 val = superclass.doMethod.call(this, attr, start, end);
4872             }
4873             return val;
4874         };
4875
4876         proto.getAttribute = function(attr) {
4877             var val = null;
4878             var el = this.getEl();
4879
4880             if (attr == 'scroll') {
4881                 val = [ el.scrollLeft, el.scrollTop ];
4882             } else {
4883                 val = superclass.getAttribute.call(this, attr);
4884             }
4885
4886             return val;
4887         };
4888
4889         proto.setAttribute = function(attr, val, unit) {
4890             var el = this.getEl();
4891
4892             if (attr == 'scroll') {
4893                 el.scrollLeft = val[0];
4894                 el.scrollTop = val[1];
4895             } else {
4896                 superclass.setAttribute.call(this, attr, val, unit);
4897             }
4898         };
4899     })();
4900 /**
4901  * Originally based of this code... - refactored for Roo...
4902  * https://github.com/aaalsaleh/undo-manager
4903  
4904  * undo-manager.js
4905  * @author  Abdulrahman Alsaleh 
4906  * @copyright 2015 Abdulrahman Alsaleh 
4907  * @license  MIT License (c) 
4908  *
4909  * Hackily modifyed by alan@roojs.com
4910  *
4911  *
4912  *  
4913  *
4914  *  TOTALLY UNTESTED...
4915  *
4916  *  Documentation to be done....
4917  */
4918  
4919
4920 /**
4921 * @class Roo.lib.UndoManager
4922 * An undo manager implementation in JavaScript. It follows the W3C UndoManager and DOM Transaction
4923 * Draft and the undocumented and disabled Mozilla Firefox's UndoManager implementation.
4924
4925  * Usage:
4926  * <pre><code>
4927
4928
4929 editor.undoManager = new Roo.lib.UndoManager(1000, editor);
4930  
4931 </code></pre>
4932
4933 * For more information see this blog post with examples:
4934 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4935      - Create Elements using DOM, HTML fragments and Templates</a>. 
4936 * @constructor
4937 * @param {Number} limit how far back to go ... use 1000?
4938 * @param {Object} scope usually use document..
4939 */
4940
4941 Roo.lib.UndoManager = function (limit, undoScopeHost)
4942 {
4943     this.stack = [];
4944     this.limit = limit;
4945     this.scope = undoScopeHost;
4946     this.fireEvent = typeof CustomEvent != 'undefined' && undoScopeHost && undoScopeHost.dispatchEvent;
4947     if (this.fireEvent) {
4948         this.bindEvents();
4949     }
4950     this.reset();
4951     
4952 };
4953         
4954 Roo.lib.UndoManager.prototype = {
4955     
4956     limit : false,
4957     stack : false,
4958     scope :  false,
4959     fireEvent : false,
4960     position : 0,
4961     length : 0,
4962     
4963     
4964      /**
4965      * To push and execute a transaction, the method undoManager.transact
4966      * must be called by passing a transaction object as the first argument, and a merge
4967      * flag as the second argument. A transaction object has the following properties:
4968      *
4969      * Usage:
4970 <pre><code>
4971 undoManager.transact({
4972     label: 'Typing',
4973     execute: function() { ... },
4974     undo: function() { ... },
4975     // redo same as execute
4976     redo: function() { this.execute(); }
4977 }, false);
4978
4979 // merge transaction
4980 undoManager.transact({
4981     label: 'Typing',
4982     execute: function() { ... },  // this will be run...
4983     undo: function() { ... }, // what to do when undo is run.
4984     // redo same as execute
4985     redo: function() { this.execute(); }
4986 }, true); 
4987 </code></pre> 
4988      *
4989      * 
4990      * @param {Object} transaction The transaction to add to the stack.
4991      * @return {String} The HTML fragment
4992      */
4993     
4994     
4995     transact : function (transaction, merge)
4996     {
4997         if (arguments.length < 2) {
4998             throw new TypeError('Not enough arguments to UndoManager.transact.');
4999         }
5000
5001         transaction.execute();
5002
5003         this.stack.splice(0, this.position);
5004         if (merge && this.length) {
5005             this.stack[0].push(transaction);
5006         } else {
5007             this.stack.unshift([transaction]);
5008         }
5009     
5010         this.position = 0;
5011
5012         if (this.limit && this.stack.length > this.limit) {
5013             this.length = this.stack.length = this.limit;
5014         } else {
5015             this.length = this.stack.length;
5016         }
5017
5018         if (this.fireEvent) {
5019             this.scope.dispatchEvent(
5020                 new CustomEvent('DOMTransaction', {
5021                     detail: {
5022                         transactions: this.stack[0].slice()
5023                     },
5024                     bubbles: true,
5025                     cancelable: false
5026                 })
5027             );
5028         }
5029         
5030         Roo.log("transaction: pos:" + this.position + " len: " + this.length + " slen:" + this.stack.length);
5031       
5032         
5033     },
5034
5035     undo : function ()
5036     {
5037         Roo.log("undo: pos:" + this.position + " len: " + this.length + " slen:" + this.stack.length);
5038         
5039         if (this.position < this.length) {
5040             for (var i = this.stack[this.position].length - 1; i >= 0; i--) {
5041                 this.stack[this.position][i].undo();
5042             }
5043             this.position++;
5044
5045             if (this.fireEvent) {
5046                 this.scope.dispatchEvent(
5047                     new CustomEvent('undo', {
5048                         detail: {
5049                             transactions: this.stack[this.position - 1].slice()
5050                         },
5051                         bubbles: true,
5052                         cancelable: false
5053                     })
5054                 );
5055             }
5056         }
5057     },
5058
5059     redo : function ()
5060     {
5061         if (this.position > 0) {
5062             for (var i = 0, n = this.stack[this.position - 1].length; i < n; i++) {
5063                 this.stack[this.position - 1][i].redo();
5064             }
5065             this.position--;
5066
5067             if (this.fireEvent) {
5068                 this.scope.dispatchEvent(
5069                     new CustomEvent('redo', {
5070                         detail: {
5071                             transactions: this.stack[this.position].slice()
5072                         },
5073                         bubbles: true,
5074                         cancelable: false
5075                     })
5076                 );
5077             }
5078         }
5079     },
5080
5081     item : function (index)
5082     {
5083         if (index >= 0 && index < this.length) {
5084             return this.stack[index].slice();
5085         }
5086         return null;
5087     },
5088
5089     clearUndo : function () {
5090         this.stack.length = this.length = this.position;
5091     },
5092
5093     clearRedo : function () {
5094         this.stack.splice(0, this.position);
5095         this.position = 0;
5096         this.length = this.stack.length;
5097     },
5098     /**
5099      * Reset the undo - probaly done on load to clear all history.
5100      */
5101     reset : function()
5102     {
5103         this.stack = [];
5104         this.position = 0;
5105         this.length = 0;
5106         this.current_html = this.scope.innerHTML;
5107         if (this.timer !== false) {
5108             clearTimeout(this.timer);
5109         }
5110         this.timer = false;
5111         this.merge = false;
5112         this.addEvent();
5113         
5114     },
5115     current_html : '',
5116     timer : false,
5117     merge : false,
5118     
5119     
5120     // this will handle the undo/redo on the element.?
5121     bindEvents : function()
5122     {
5123         var el  = this.scope;
5124         el.undoManager = this;
5125         
5126         
5127         this.scope.addEventListener('keydown', function(e) {
5128             if ((e.ctrlKey || e.metaKey) && e.keyCode === 90) {
5129                 if (e.shiftKey) {
5130                     el.undoManager.redo(); // Ctrl/Command + Shift + Z
5131                 } else {
5132                     el.undoManager.undo(); // Ctrl/Command + Z
5133                 }
5134         
5135                 e.preventDefault();
5136             }
5137         });
5138         /// ignore keyup..
5139         this.scope.addEventListener('keyup', function(e) {
5140             if ((e.ctrlKey || e.metaKey) && e.keyCode === 90) {
5141                 e.preventDefault();
5142             }
5143         });
5144         
5145         
5146         
5147         var t = this;
5148         
5149         el.addEventListener('input', function(e) {
5150             if(el.innerHTML == t.current_html) {
5151                 return;
5152             }
5153             // only record events every second.
5154             if (t.timer !== false) {
5155                clearTimeout(t.timer);
5156                t.timer = false;
5157             }
5158             t.timer = setTimeout(function() { t.merge = false; }, 1000);
5159             
5160             t.addEvent(t.merge);
5161             t.merge = true; // ignore changes happening every second..
5162         });
5163         },
5164     /**
5165      * Manually add an event.
5166      * Normall called without arguements - and it will just get added to the stack.
5167      * 
5168      */
5169     
5170     addEvent : function(merge)
5171     {
5172         Roo.log("undomanager +" + (merge ? 'Y':'n'));
5173         // not sure if this should clear the timer 
5174         merge = typeof(merge) == 'undefined' ? false : merge; 
5175         
5176         this.scope.undoManager.transact({
5177             scope : this.scope,
5178             oldHTML: this.current_html,
5179             newHTML: this.scope.innerHTML,
5180             // nothing to execute (content already changed when input is fired)
5181             execute: function() { },
5182             undo: function() {
5183                 this.scope.innerHTML = this.current_html = this.oldHTML;
5184             },
5185             redo: function() {
5186                 this.scope.innerHTML = this.current_html = this.newHTML;
5187             }
5188         }, false); //merge);
5189         
5190         this.merge = merge;
5191         
5192         this.current_html = this.scope.innerHTML;
5193     }
5194     
5195     
5196      
5197     
5198     
5199     
5200 };
5201 /*
5202  * Based on:
5203  * Ext JS Library 1.1.1
5204  * Copyright(c) 2006-2007, Ext JS, LLC.
5205  *
5206  * Originally Released Under LGPL - original licence link has changed is not relivant.
5207  *
5208  * Fork - LGPL
5209  * <script type="text/javascript">
5210  */
5211
5212
5213 // nasty IE9 hack - what a pile of crap that is..
5214
5215  if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
5216     Range.prototype.createContextualFragment = function (html) {
5217         var doc = window.document;
5218         var container = doc.createElement("div");
5219         container.innerHTML = html;
5220         var frag = doc.createDocumentFragment(), n;
5221         while ((n = container.firstChild)) {
5222             frag.appendChild(n);
5223         }
5224         return frag;
5225     };
5226 }
5227
5228 /**
5229  * @class Roo.DomHelper
5230  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
5231  * For more information see <a href="http://web.archive.org/web/20071221063734/http://www.jackslocum.com/blog/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">this blog post with examples</a>.
5232  * @static
5233  */
5234 Roo.DomHelper = function(){
5235     var tempTableEl = null;
5236     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
5237     var tableRe = /^table|tbody|tr|td$/i;
5238     var xmlns = {};
5239     // build as innerHTML where available
5240     /** @ignore */
5241     var createHtml = function(o){
5242         if(typeof o == 'string'){
5243             return o;
5244         }
5245         var b = "";
5246         if(!o.tag){
5247             o.tag = "div";
5248         }
5249         b += "<" + o.tag;
5250         for(var attr in o){
5251             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") { continue; }
5252             if(attr == "style"){
5253                 var s = o["style"];
5254                 if(typeof s == "function"){
5255                     s = s.call();
5256                 }
5257                 if(typeof s == "string"){
5258                     b += ' style="' + s + '"';
5259                 }else if(typeof s == "object"){
5260                     b += ' style="';
5261                     for(var key in s){
5262                         if(typeof s[key] != "function"){
5263                             b += key + ":" + s[key] + ";";
5264                         }
5265                     }
5266                     b += '"';
5267                 }
5268             }else{
5269                 if(attr == "cls"){
5270                     b += ' class="' + o["cls"] + '"';
5271                 }else if(attr == "htmlFor"){
5272                     b += ' for="' + o["htmlFor"] + '"';
5273                 }else{
5274                     b += " " + attr + '="' + o[attr] + '"';
5275                 }
5276             }
5277         }
5278         if(emptyTags.test(o.tag)){
5279             b += "/>";
5280         }else{
5281             b += ">";
5282             var cn = o.children || o.cn;
5283             if(cn){
5284                 //http://bugs.kde.org/show_bug.cgi?id=71506
5285                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
5286                     for(var i = 0, len = cn.length; i < len; i++) {
5287                         b += createHtml(cn[i], b);
5288                     }
5289                 }else{
5290                     b += createHtml(cn, b);
5291                 }
5292             }
5293             if(o.html){
5294                 b += o.html;
5295             }
5296             b += "</" + o.tag + ">";
5297         }
5298         return b;
5299     };
5300
5301     // build as dom
5302     /** @ignore */
5303     var createDom = function(o, parentNode){
5304          
5305         // defininition craeted..
5306         var ns = false;
5307         if (o.ns && o.ns != 'html') {
5308                
5309             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
5310                 xmlns[o.ns] = o.xmlns;
5311                 ns = o.xmlns;
5312             }
5313             if (typeof(xmlns[o.ns]) == 'undefined') {
5314                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
5315             }
5316             ns = xmlns[o.ns];
5317         }
5318         
5319         
5320         if (typeof(o) == 'string') {
5321             return parentNode.appendChild(document.createTextNode(o));
5322         }
5323         o.tag = o.tag || div;
5324         if (o.ns && Roo.isIE) {
5325             ns = false;
5326             o.tag = o.ns + ':' + o.tag;
5327             
5328         }
5329         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
5330         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
5331         for(var attr in o){
5332             
5333             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
5334                     attr == "style" || typeof o[attr] == "function") { continue; }
5335                     
5336             if(attr=="cls" && Roo.isIE){
5337                 el.className = o["cls"];
5338             }else{
5339                 if(useSet) { el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);}
5340                 else { 
5341                     el[attr] = o[attr];
5342                 }
5343             }
5344         }
5345         Roo.DomHelper.applyStyles(el, o.style);
5346         var cn = o.children || o.cn;
5347         if(cn){
5348             //http://bugs.kde.org/show_bug.cgi?id=71506
5349              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
5350                 for(var i = 0, len = cn.length; i < len; i++) {
5351                     createDom(cn[i], el);
5352                 }
5353             }else{
5354                 createDom(cn, el);
5355             }
5356         }
5357         if(o.html){
5358             el.innerHTML = o.html;
5359         }
5360         if(parentNode){
5361            parentNode.appendChild(el);
5362         }
5363         return el;
5364     };
5365
5366     var ieTable = function(depth, s, h, e){
5367         tempTableEl.innerHTML = [s, h, e].join('');
5368         var i = -1, el = tempTableEl;
5369         while(++i < depth && el.firstChild){
5370             el = el.firstChild;
5371         }
5372         return el;
5373     };
5374
5375     // kill repeat to save bytes
5376     var ts = '<table>',
5377         te = '</table>',
5378         tbs = ts+'<tbody>',
5379         tbe = '</tbody>'+te,
5380         trs = tbs + '<tr>',
5381         tre = '</tr>'+tbe;
5382
5383     /**
5384      * @ignore
5385      * Nasty code for IE's broken table implementation
5386      */
5387     var insertIntoTable = function(tag, where, el, html){
5388         if(!tempTableEl){
5389             tempTableEl = document.createElement('div');
5390         }
5391         var node;
5392         var before = null;
5393         if(tag == 'td'){
5394             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
5395                 return;
5396             }
5397             if(where == 'beforebegin'){
5398                 before = el;
5399                 el = el.parentNode;
5400             } else{
5401                 before = el.nextSibling;
5402                 el = el.parentNode;
5403             }
5404             node = ieTable(4, trs, html, tre);
5405         }
5406         else if(tag == 'tr'){
5407             if(where == 'beforebegin'){
5408                 before = el;
5409                 el = el.parentNode;
5410                 node = ieTable(3, tbs, html, tbe);
5411             } else if(where == 'afterend'){
5412                 before = el.nextSibling;
5413                 el = el.parentNode;
5414                 node = ieTable(3, tbs, html, tbe);
5415             } else{ // INTO a TR
5416                 if(where == 'afterbegin'){
5417                     before = el.firstChild;
5418                 }
5419                 node = ieTable(4, trs, html, tre);
5420             }
5421         } else if(tag == 'tbody'){
5422             if(where == 'beforebegin'){
5423                 before = el;
5424                 el = el.parentNode;
5425                 node = ieTable(2, ts, html, te);
5426             } else if(where == 'afterend'){
5427                 before = el.nextSibling;
5428                 el = el.parentNode;
5429                 node = ieTable(2, ts, html, te);
5430             } else{
5431                 if(where == 'afterbegin'){
5432                     before = el.firstChild;
5433                 }
5434                 node = ieTable(3, tbs, html, tbe);
5435             }
5436         } else{ // TABLE
5437             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
5438                 return;
5439             }
5440             if(where == 'afterbegin'){
5441                 before = el.firstChild;
5442             }
5443             node = ieTable(2, ts, html, te);
5444         }
5445         el.insertBefore(node, before);
5446         return node;
5447     };
5448     
5449     // this is a bit like the react update code...
5450     // 
5451     
5452     var updateNode = function(from, to)
5453     {
5454         // should we handle non-standard elements?
5455         Roo.log(["UpdateNode" , from, to]);
5456         if (from.nodeType != to.nodeType) {
5457             Roo.log(["ReplaceChild - mismatch notType" , to, from ]);
5458             from.parentNode.replaceChild(to, from);
5459         }
5460         
5461         if (from.nodeType == 3) {
5462             // assume it's text?!
5463             if (from.data == to.data) {
5464                 return;
5465             }
5466             from.data = to.data;
5467             return;
5468         }
5469         
5470         // assume 'to' doesnt have '1/3 nodetypes!
5471         if (from.nodeType !=1 || from.tagName != to.tagName) {
5472             Roo.log(["ReplaceChild" , from, to ]);
5473             from.parentNode.replaceChild(to, from);
5474             return;
5475         }
5476         // compare attributes
5477         var ar = Array.from(from.attributes);
5478         for(var i = 0; i< ar.length;i++) {
5479             if (to.hasAttribute(ar[i].name)) {
5480                 continue;
5481             }
5482             if (ar[i].name == 'id') { // always keep ids?
5483                continue;
5484             }
5485             if (ar[i].name == 'style') {
5486                throw "style removed?";
5487             }
5488             Roo.log("removeAttribute" + ar[i].name);
5489             from.removeAttribute(ar[i].name);
5490         }
5491         ar = to.attributes;
5492         for(var i = 0; i< ar.length;i++) {
5493             if (from.getAttribute(ar[i].name) == to.getAttribute(ar[i].name)) {
5494                 continue;
5495             }
5496             Roo.log("updateAttribute " + from.getAttribute(ar[i].name) + '=>' + to.getAttribute(ar[i].name));
5497             from.setAttribute(ar[i].name, to.getAttribute(ar[i].name));
5498         }
5499         // children
5500         var far = Array.from(from.childNodes);
5501         var tar = Array.from(to.childNodes);
5502         // if the lengths are different.. then it's probably a editable content change, rather than
5503         // a change of the block definition..
5504         
5505         // this did notwork , as our rebuilt nodes did not include ID's so did not match at all.
5506          /*if (from.innerHTML == to.innerHTML) {
5507             return;
5508         }
5509         if (far.length != tar.length) {
5510             from.innerHTML = to.innerHTML;
5511             return;
5512         }
5513         */
5514         
5515         for(var i = 0; i < Math.max(tar.length, far.length); i++) {
5516             if (i >= far.length) {
5517                 from.appendChild(tar[i]);
5518                 Roo.log(["add", tar[i]]);
5519                 
5520             } else if ( i  >= tar.length) {
5521                 from.removeChild(far[i]);
5522                 Roo.log(["remove", far[i]]);
5523             } else {
5524                 
5525                 updateNode(far[i], tar[i]);
5526             }    
5527         }
5528         
5529         
5530         
5531         
5532     };
5533     
5534     
5535
5536     return {
5537         /** True to force the use of DOM instead of html fragments @type Boolean */
5538         useDom : false,
5539     
5540         /**
5541          * Returns the markup for the passed Element(s) config
5542          * @param {Object} o The Dom object spec (and children)
5543          * @return {String}
5544          */
5545         markup : function(o){
5546             return createHtml(o);
5547         },
5548     
5549         /**
5550          * Applies a style specification to an element
5551          * @param {String/HTMLElement} el The element to apply styles to
5552          * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
5553          * a function which returns such a specification.
5554          */
5555         applyStyles : function(el, styles){
5556             if(styles){
5557                el = Roo.fly(el);
5558                if(typeof styles == "string"){
5559                    var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
5560                    var matches;
5561                    while ((matches = re.exec(styles)) != null){
5562                        el.setStyle(matches[1], matches[2]);
5563                    }
5564                }else if (typeof styles == "object"){
5565                    for (var style in styles){
5566                       el.setStyle(style, styles[style]);
5567                    }
5568                }else if (typeof styles == "function"){
5569                     Roo.DomHelper.applyStyles(el, styles.call());
5570                }
5571             }
5572         },
5573     
5574         /**
5575          * Inserts an HTML fragment into the Dom
5576          * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
5577          * @param {HTMLElement} el The context element
5578          * @param {String} html The HTML fragmenet
5579          * @return {HTMLElement} The new node
5580          */
5581         insertHtml : function(where, el, html){
5582             where = where.toLowerCase();
5583             if(el.insertAdjacentHTML){
5584                 if(tableRe.test(el.tagName)){
5585                     var rs;
5586                     if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
5587                         return rs;
5588                     }
5589                 }
5590                 switch(where){
5591                     case "beforebegin":
5592                         el.insertAdjacentHTML('BeforeBegin', html);
5593                         return el.previousSibling;
5594                     case "afterbegin":
5595                         el.insertAdjacentHTML('AfterBegin', html);
5596                         return el.firstChild;
5597                     case "beforeend":
5598                         el.insertAdjacentHTML('BeforeEnd', html);
5599                         return el.lastChild;
5600                     case "afterend":
5601                         el.insertAdjacentHTML('AfterEnd', html);
5602                         return el.nextSibling;
5603                 }
5604                 throw 'Illegal insertion point -> "' + where + '"';
5605             }
5606             var range = el.ownerDocument.createRange();
5607             var frag;
5608             switch(where){
5609                  case "beforebegin":
5610                     range.setStartBefore(el);
5611                     frag = range.createContextualFragment(html);
5612                     el.parentNode.insertBefore(frag, el);
5613                     return el.previousSibling;
5614                  case "afterbegin":
5615                     if(el.firstChild){
5616                         range.setStartBefore(el.firstChild);
5617                         frag = range.createContextualFragment(html);
5618                         el.insertBefore(frag, el.firstChild);
5619                         return el.firstChild;
5620                     }else{
5621                         el.innerHTML = html;
5622                         return el.firstChild;
5623                     }
5624                 case "beforeend":
5625                     if(el.lastChild){
5626                         range.setStartAfter(el.lastChild);
5627                         frag = range.createContextualFragment(html);
5628                         el.appendChild(frag);
5629                         return el.lastChild;
5630                     }else{
5631                         el.innerHTML = html;
5632                         return el.lastChild;
5633                     }
5634                 case "afterend":
5635                     range.setStartAfter(el);
5636                     frag = range.createContextualFragment(html);
5637                     el.parentNode.insertBefore(frag, el.nextSibling);
5638                     return el.nextSibling;
5639                 }
5640                 throw 'Illegal insertion point -> "' + where + '"';
5641         },
5642     
5643         /**
5644          * Creates new Dom element(s) and inserts them before el
5645          * @param {String/HTMLElement/Element} el The context element
5646          * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5647          * @param {Boolean} returnElement (optional) true to return a Roo.Element
5648          * @return {HTMLElement/Roo.Element} The new node
5649          */
5650         insertBefore : function(el, o, returnElement){
5651             return this.doInsert(el, o, returnElement, "beforeBegin");
5652         },
5653     
5654         /**
5655          * Creates new Dom element(s) and inserts them after el
5656          * @param {String/HTMLElement/Element} el The context element
5657          * @param {Object} o The Dom object spec (and children)
5658          * @param {Boolean} returnElement (optional) true to return a Roo.Element
5659          * @return {HTMLElement/Roo.Element} The new node
5660          */
5661         insertAfter : function(el, o, returnElement){
5662             return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
5663         },
5664     
5665         /**
5666          * Creates new Dom element(s) and inserts them as the first child of el
5667          * @param {String/HTMLElement/Element} el The context element
5668          * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5669          * @param {Boolean} returnElement (optional) true to return a Roo.Element
5670          * @return {HTMLElement/Roo.Element} The new node
5671          */
5672         insertFirst : function(el, o, returnElement){
5673             return this.doInsert(el, o, returnElement, "afterBegin");
5674         },
5675     
5676         // private
5677         doInsert : function(el, o, returnElement, pos, sibling){
5678             el = Roo.getDom(el);
5679             var newNode;
5680             if(this.useDom || o.ns){
5681                 newNode = createDom(o, null);
5682                 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
5683             }else{
5684                 var html = createHtml(o);
5685                 newNode = this.insertHtml(pos, el, html);
5686             }
5687             return returnElement ? Roo.get(newNode, true) : newNode;
5688         },
5689     
5690         /**
5691          * Creates new Dom element(s) and appends them to el
5692          * @param {String/HTMLElement/Element} el The context element
5693          * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5694          * @param {Boolean} returnElement (optional) true to return a Roo.Element
5695          * @return {HTMLElement/Roo.Element} The new node
5696          */
5697         append : function(el, o, returnElement){
5698             el = Roo.getDom(el);
5699             var newNode;
5700             if(this.useDom || o.ns){
5701                 newNode = createDom(o, null);
5702                 el.appendChild(newNode);
5703             }else{
5704                 var html = createHtml(o);
5705                 newNode = this.insertHtml("beforeEnd", el, html);
5706             }
5707             return returnElement ? Roo.get(newNode, true) : newNode;
5708         },
5709     
5710         /**
5711          * Creates new Dom element(s) and overwrites the contents of el with them
5712          * @param {String/HTMLElement/Element} el The context element
5713          * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5714          * @param {Boolean} returnElement (optional) true to return a Roo.Element
5715          * @return {HTMLElement/Roo.Element} The new node
5716          */
5717         overwrite : function(el, o, returnElement)
5718         {
5719             el = Roo.getDom(el);
5720             if (o.ns) {
5721               
5722                 while (el.childNodes.length) {
5723                     el.removeChild(el.firstChild);
5724                 }
5725                 createDom(o, el);
5726             } else {
5727                 el.innerHTML = createHtml(o);   
5728             }
5729             
5730             return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
5731         },
5732     
5733         /**
5734          * Creates a new Roo.DomHelper.Template from the Dom object spec
5735          * @param {Object} o The Dom object spec (and children)
5736          * @return {Roo.DomHelper.Template} The new template
5737          */
5738         createTemplate : function(o){
5739             var html = createHtml(o);
5740             return new Roo.Template(html);
5741         },
5742          /**
5743          * Updates the first element with the spec from the o (replacing if necessary)
5744          * This iterates through the children, and updates attributes / children etc..
5745          * @param {String/HTMLElement/Element} el The context element
5746          * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5747          */
5748         
5749         update : function(el, o)
5750         {
5751             updateNode(Roo.getDom(el), createDom(o));
5752             
5753         }
5754         
5755         
5756     };
5757 }();
5758 /*
5759  * Based on:
5760  * Ext JS Library 1.1.1
5761  * Copyright(c) 2006-2007, Ext JS, LLC.
5762  *
5763  * Originally Released Under LGPL - original licence link has changed is not relivant.
5764  *
5765  * Fork - LGPL
5766  * <script type="text/javascript">
5767  */
5768  
5769 /**
5770 * @class Roo.Template
5771 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
5772 * For a list of available format functions, see {@link Roo.util.Format}.<br />
5773 * Usage:
5774 <pre><code>
5775 var t = new Roo.Template({
5776     html :  '&lt;div name="{id}"&gt;' + 
5777         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
5778         '&lt;/div&gt;',
5779     myformat: function (value, allValues) {
5780         return 'XX' + value;
5781     }
5782 });
5783 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
5784 </code></pre>
5785 * For more information see this blog post with examples:
5786 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
5787      - Create Elements using DOM, HTML fragments and Templates</a>. 
5788 * @constructor
5789 * @param {Object} cfg - Configuration object.
5790 */
5791 Roo.Template = function(cfg){
5792     // BC!
5793     if(cfg instanceof Array){
5794         cfg = cfg.join("");
5795     }else if(arguments.length > 1){
5796         cfg = Array.prototype.join.call(arguments, "");
5797     }
5798     
5799     
5800     if (typeof(cfg) == 'object') {
5801         Roo.apply(this,cfg)
5802     } else {
5803         // bc
5804         this.html = cfg;
5805     }
5806     if (this.url) {
5807         this.load();
5808     }
5809     
5810 };
5811 Roo.Template.prototype = {
5812     
5813     /**
5814      * @cfg {Function} onLoad Called after the template has been loaded and complied (usually from a remove source)
5815      */
5816     onLoad : false,
5817     
5818     
5819     /**
5820      * @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..
5821      *                    it should be fixed so that template is observable...
5822      */
5823     url : false,
5824     /**
5825      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
5826      */
5827     html : '',
5828     
5829     
5830     compiled : false,
5831     loaded : false,
5832     /**
5833      * Returns an HTML fragment of this template with the specified values applied.
5834      * @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'})
5835      * @return {String} The HTML fragment
5836      */
5837     
5838    
5839     
5840     applyTemplate : function(values){
5841         //Roo.log(["applyTemplate", values]);
5842         try {
5843            
5844             if(this.compiled){
5845                 return this.compiled(values);
5846             }
5847             var useF = this.disableFormats !== true;
5848             var fm = Roo.util.Format, tpl = this;
5849             var fn = function(m, name, format, args){
5850                 if(format && useF){
5851                     if(format.substr(0, 5) == "this."){
5852                         return tpl.call(format.substr(5), values[name], values);
5853                     }else{
5854                         if(args){
5855                             // quoted values are required for strings in compiled templates, 
5856                             // but for non compiled we need to strip them
5857                             // quoted reversed for jsmin
5858                             var re = /^\s*['"](.*)["']\s*$/;
5859                             args = args.split(',');
5860                             for(var i = 0, len = args.length; i < len; i++){
5861                                 args[i] = args[i].replace(re, "$1");
5862                             }
5863                             args = [values[name]].concat(args);
5864                         }else{
5865                             args = [values[name]];
5866                         }
5867                         return fm[format].apply(fm, args);
5868                     }
5869                 }else{
5870                     return values[name] !== undefined ? values[name] : "";
5871                 }
5872             };
5873             return this.html.replace(this.re, fn);
5874         } catch (e) {
5875             Roo.log(e);
5876             throw e;
5877         }
5878          
5879     },
5880     
5881     loading : false,
5882       
5883     load : function ()
5884     {
5885          
5886         if (this.loading) {
5887             return;
5888         }
5889         var _t = this;
5890         
5891         this.loading = true;
5892         this.compiled = false;
5893         
5894         var cx = new Roo.data.Connection();
5895         cx.request({
5896             url : this.url,
5897             method : 'GET',
5898             success : function (response) {
5899                 _t.loading = false;
5900                 _t.url = false;
5901                 
5902                 _t.set(response.responseText,true);
5903                 _t.loaded = true;
5904                 if (_t.onLoad) {
5905                     _t.onLoad();
5906                 }
5907              },
5908             failure : function(response) {
5909                 Roo.log("Template failed to load from " + _t.url);
5910                 _t.loading = false;
5911             }
5912         });
5913     },
5914
5915     /**
5916      * Sets the HTML used as the template and optionally compiles it.
5917      * @param {String} html
5918      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
5919      * @return {Roo.Template} this
5920      */
5921     set : function(html, compile){
5922         this.html = html;
5923         this.compiled = false;
5924         if(compile){
5925             this.compile();
5926         }
5927         return this;
5928     },
5929     
5930     /**
5931      * True to disable format functions (defaults to false)
5932      * @type Boolean
5933      */
5934     disableFormats : false,
5935     
5936     /**
5937     * The regular expression used to match template variables 
5938     * @type RegExp
5939     * @property 
5940     */
5941     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
5942     
5943     /**
5944      * Compiles the template into an internal function, eliminating the RegEx overhead.
5945      * @return {Roo.Template} this
5946      */
5947     compile : function(){
5948         var fm = Roo.util.Format;
5949         var useF = this.disableFormats !== true;
5950         var sep = Roo.isGecko ? "+" : ",";
5951         var fn = function(m, name, format, args){
5952             if(format && useF){
5953                 args = args ? ',' + args : "";
5954                 if(format.substr(0, 5) != "this."){
5955                     format = "fm." + format + '(';
5956                 }else{
5957                     format = 'this.call("'+ format.substr(5) + '", ';
5958                     args = ", values";
5959                 }
5960             }else{
5961                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
5962             }
5963             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
5964         };
5965         var body;
5966         // branched to use + in gecko and [].join() in others
5967         if(Roo.isGecko){
5968             body = "this.compiled = function(values){ return '" +
5969                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
5970                     "';};";
5971         }else{
5972             body = ["this.compiled = function(values){ return ['"];
5973             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
5974             body.push("'].join('');};");
5975             body = body.join('');
5976         }
5977         /**
5978          * eval:var:values
5979          * eval:var:fm
5980          */
5981         eval(body);
5982         return this;
5983     },
5984     
5985     // private function used to call members
5986     call : function(fnName, value, allValues){
5987         return this[fnName](value, allValues);
5988     },
5989     
5990     /**
5991      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
5992      * @param {String/HTMLElement/Roo.Element} el The context element
5993      * @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'})
5994      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
5995      * @return {HTMLElement/Roo.Element} The new node or Element
5996      */
5997     insertFirst: function(el, values, returnElement){
5998         return this.doInsert('afterBegin', el, values, returnElement);
5999     },
6000
6001     /**
6002      * Applies the supplied values to the template and inserts the new node(s) before 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     insertBefore: function(el, values, returnElement){
6009         return this.doInsert('beforeBegin', el, values, returnElement);
6010     },
6011
6012     /**
6013      * Applies the supplied values to the template and inserts the new node(s) after 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     insertAfter : function(el, values, returnElement){
6020         return this.doInsert('afterEnd', el, values, returnElement);
6021     },
6022     
6023     /**
6024      * Applies the supplied values to the template and appends the new node(s) to 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     append : function(el, values, returnElement){
6031         return this.doInsert('beforeEnd', el, values, returnElement);
6032     },
6033
6034     doInsert : function(where, el, values, returnEl){
6035         el = Roo.getDom(el);
6036         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
6037         return returnEl ? Roo.get(newNode, true) : newNode;
6038     },
6039
6040     /**
6041      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
6042      * @param {String/HTMLElement/Roo.Element} el The context element
6043      * @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'})
6044      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
6045      * @return {HTMLElement/Roo.Element} The new node or Element
6046      */
6047     overwrite : function(el, values, returnElement){
6048         el = Roo.getDom(el);
6049         el.innerHTML = this.applyTemplate(values);
6050         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
6051     }
6052 };
6053 /**
6054  * Alias for {@link #applyTemplate}
6055  * @method
6056  */
6057 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
6058
6059 // backwards compat
6060 Roo.DomHelper.Template = Roo.Template;
6061
6062 /**
6063  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
6064  * @param {String/HTMLElement} el A DOM element or its id
6065  * @returns {Roo.Template} The created template
6066  * @static
6067  */
6068 Roo.Template.from = function(el){
6069     el = Roo.getDom(el);
6070     return new Roo.Template(el.value || el.innerHTML);
6071 };/*
6072  * Based on:
6073  * Ext JS Library 1.1.1
6074  * Copyright(c) 2006-2007, Ext JS, LLC.
6075  *
6076  * Originally Released Under LGPL - original licence link has changed is not relivant.
6077  *
6078  * Fork - LGPL
6079  * <script type="text/javascript">
6080  */
6081  
6082
6083 /*
6084  * This is code is also distributed under MIT license for use
6085  * with jQuery and prototype JavaScript libraries.
6086  */
6087 /**
6088  * @class Roo.DomQuery
6089 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).
6090 <p>
6091 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>
6092
6093 <p>
6094 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.
6095 </p>
6096 <h4>Element Selectors:</h4>
6097 <ul class="list">
6098     <li> <b>*</b> any element</li>
6099     <li> <b>E</b> an element with the tag E</li>
6100     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
6101     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
6102     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
6103     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
6104 </ul>
6105 <h4>Attribute Selectors:</h4>
6106 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
6107 <ul class="list">
6108     <li> <b>E[foo]</b> has an attribute "foo"</li>
6109     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
6110     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
6111     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
6112     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
6113     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
6114     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
6115 </ul>
6116 <h4>Pseudo Classes:</h4>
6117 <ul class="list">
6118     <li> <b>E:first-child</b> E is the first child of its parent</li>
6119     <li> <b>E:last-child</b> E is the last child of its parent</li>
6120     <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>
6121     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
6122     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
6123     <li> <b>E:only-child</b> E is the only child of its parent</li>
6124     <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>
6125     <li> <b>E:first</b> the first E in the resultset</li>
6126     <li> <b>E:last</b> the last E in the resultset</li>
6127     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
6128     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
6129     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
6130     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
6131     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
6132     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
6133     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
6134     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
6135     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
6136 </ul>
6137 <h4>CSS Value Selectors:</h4>
6138 <ul class="list">
6139     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
6140     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
6141     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
6142     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
6143     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
6144     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
6145 </ul>
6146  * @static
6147  */
6148 Roo.DomQuery = function(){
6149     var cache = {}, simpleCache = {}, valueCache = {};
6150     var nonSpace = /\S/;
6151     var trimRe = /^\s+|\s+$/g;
6152     var tplRe = /\{(\d+)\}/g;
6153     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
6154     var tagTokenRe = /^(#)?([\w-\*]+)/;
6155     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
6156
6157     function child(p, index){
6158         var i = 0;
6159         var n = p.firstChild;
6160         while(n){
6161             if(n.nodeType == 1){
6162                if(++i == index){
6163                    return n;
6164                }
6165             }
6166             n = n.nextSibling;
6167         }
6168         return null;
6169     };
6170
6171     function next(n){
6172         while((n = n.nextSibling) && n.nodeType != 1);
6173         return n;
6174     };
6175
6176     function prev(n){
6177         while((n = n.previousSibling) && n.nodeType != 1);
6178         return n;
6179     };
6180
6181     function children(d){
6182         var n = d.firstChild, ni = -1;
6183             while(n){
6184                 var nx = n.nextSibling;
6185                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
6186                     d.removeChild(n);
6187                 }else{
6188                     n.nodeIndex = ++ni;
6189                 }
6190                 n = nx;
6191             }
6192             return this;
6193         };
6194
6195     function byClassName(c, a, v){
6196         if(!v){
6197             return c;
6198         }
6199         var r = [], ri = -1, cn;
6200         for(var i = 0, ci; ci = c[i]; i++){
6201             
6202             
6203             if((' '+
6204                 ( (ci instanceof SVGElement) ? ci.className.baseVal : ci.className)
6205                  +' ').indexOf(v) != -1){
6206                 r[++ri] = ci;
6207             }
6208         }
6209         return r;
6210     };
6211
6212     function attrValue(n, attr){
6213         if(!n.tagName && typeof n.length != "undefined"){
6214             n = n[0];
6215         }
6216         if(!n){
6217             return null;
6218         }
6219         if(attr == "for"){
6220             return n.htmlFor;
6221         }
6222         if(attr == "class" || attr == "className"){
6223             return (n instanceof SVGElement) ? n.className.baseVal : n.className;
6224         }
6225         return n.getAttribute(attr) || n[attr];
6226
6227     };
6228
6229     function getNodes(ns, mode, tagName){
6230         var result = [], ri = -1, cs;
6231         if(!ns){
6232             return result;
6233         }
6234         tagName = tagName || "*";
6235         if(typeof ns.getElementsByTagName != "undefined"){
6236             ns = [ns];
6237         }
6238         if(!mode){
6239             for(var i = 0, ni; ni = ns[i]; i++){
6240                 cs = ni.getElementsByTagName(tagName);
6241                 for(var j = 0, ci; ci = cs[j]; j++){
6242                     result[++ri] = ci;
6243                 }
6244             }
6245         }else if(mode == "/" || mode == ">"){
6246             var utag = tagName.toUpperCase();
6247             for(var i = 0, ni, cn; ni = ns[i]; i++){
6248                 cn = ni.children || ni.childNodes;
6249                 for(var j = 0, cj; cj = cn[j]; j++){
6250                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
6251                         result[++ri] = cj;
6252                     }
6253                 }
6254             }
6255         }else if(mode == "+"){
6256             var utag = tagName.toUpperCase();
6257             for(var i = 0, n; n = ns[i]; i++){
6258                 while((n = n.nextSibling) && n.nodeType != 1);
6259                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
6260                     result[++ri] = n;
6261                 }
6262             }
6263         }else if(mode == "~"){
6264             for(var i = 0, n; n = ns[i]; i++){
6265                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
6266                 if(n){
6267                     result[++ri] = n;
6268                 }
6269             }
6270         }
6271         return result;
6272     };
6273
6274     function concat(a, b){
6275         if(b.slice){
6276             return a.concat(b);
6277         }
6278         for(var i = 0, l = b.length; i < l; i++){
6279             a[a.length] = b[i];
6280         }
6281         return a;
6282     }
6283
6284     function byTag(cs, tagName){
6285         if(cs.tagName || cs == document){
6286             cs = [cs];
6287         }
6288         if(!tagName){
6289             return cs;
6290         }
6291         var r = [], ri = -1;
6292         tagName = tagName.toLowerCase();
6293         for(var i = 0, ci; ci = cs[i]; i++){
6294             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
6295                 r[++ri] = ci;
6296             }
6297         }
6298         return r;
6299     };
6300
6301     function byId(cs, attr, id){
6302         if(cs.tagName || cs == document){
6303             cs = [cs];
6304         }
6305         if(!id){
6306             return cs;
6307         }
6308         var r = [], ri = -1;
6309         for(var i = 0,ci; ci = cs[i]; i++){
6310             if(ci && ci.id == id){
6311                 r[++ri] = ci;
6312                 return r;
6313             }
6314         }
6315         return r;
6316     };
6317
6318     function byAttribute(cs, attr, value, op, custom){
6319         var r = [], ri = -1, st = custom=="{";
6320         var f = Roo.DomQuery.operators[op];
6321         for(var i = 0, ci; ci = cs[i]; i++){
6322             var a;
6323             if(st){
6324                 a = Roo.DomQuery.getStyle(ci, attr);
6325             }
6326             else if(attr == "class" || attr == "className"){
6327                 a = (ci instanceof SVGElement) ? ci.className.baseVal : ci.className;
6328             }else if(attr == "for"){
6329                 a = ci.htmlFor;
6330             }else if(attr == "href"){
6331                 a = ci.getAttribute("href", 2);
6332             }else{
6333                 a = ci.getAttribute(attr);
6334             }
6335             if((f && f(a, value)) || (!f && a)){
6336                 r[++ri] = ci;
6337             }
6338         }
6339         return r;
6340     };
6341
6342     function byPseudo(cs, name, value){
6343         return Roo.DomQuery.pseudos[name](cs, value);
6344     };
6345
6346     // This is for IE MSXML which does not support expandos.
6347     // IE runs the same speed using setAttribute, however FF slows way down
6348     // and Safari completely fails so they need to continue to use expandos.
6349     var isIE = window.ActiveXObject ? true : false;
6350
6351     // this eval is stop the compressor from
6352     // renaming the variable to something shorter
6353     
6354     /** eval:var:batch */
6355     var batch = 30803; 
6356
6357     var key = 30803;
6358
6359     function nodupIEXml(cs){
6360         var d = ++key;
6361         cs[0].setAttribute("_nodup", d);
6362         var r = [cs[0]];
6363         for(var i = 1, len = cs.length; i < len; i++){
6364             var c = cs[i];
6365             if(!c.getAttribute("_nodup") != d){
6366                 c.setAttribute("_nodup", d);
6367                 r[r.length] = c;
6368             }
6369         }
6370         for(var i = 0, len = cs.length; i < len; i++){
6371             cs[i].removeAttribute("_nodup");
6372         }
6373         return r;
6374     }
6375
6376     function nodup(cs){
6377         if(!cs){
6378             return [];
6379         }
6380         var len = cs.length, c, i, r = cs, cj, ri = -1;
6381         if(!len || typeof cs.nodeType != "undefined" || len == 1){
6382             return cs;
6383         }
6384         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
6385             return nodupIEXml(cs);
6386         }
6387         var d = ++key;
6388         cs[0]._nodup = d;
6389         for(i = 1; c = cs[i]; i++){
6390             if(c._nodup != d){
6391                 c._nodup = d;
6392             }else{
6393                 r = [];
6394                 for(var j = 0; j < i; j++){
6395                     r[++ri] = cs[j];
6396                 }
6397                 for(j = i+1; cj = cs[j]; j++){
6398                     if(cj._nodup != d){
6399                         cj._nodup = d;
6400                         r[++ri] = cj;
6401                     }
6402                 }
6403                 return r;
6404             }
6405         }
6406         return r;
6407     }
6408
6409     function quickDiffIEXml(c1, c2){
6410         var d = ++key;
6411         for(var i = 0, len = c1.length; i < len; i++){
6412             c1[i].setAttribute("_qdiff", d);
6413         }
6414         var r = [];
6415         for(var i = 0, len = c2.length; i < len; i++){
6416             if(c2[i].getAttribute("_qdiff") != d){
6417                 r[r.length] = c2[i];
6418             }
6419         }
6420         for(var i = 0, len = c1.length; i < len; i++){
6421            c1[i].removeAttribute("_qdiff");
6422         }
6423         return r;
6424     }
6425
6426     function quickDiff(c1, c2){
6427         var len1 = c1.length;
6428         if(!len1){
6429             return c2;
6430         }
6431         if(isIE && c1[0].selectSingleNode){
6432             return quickDiffIEXml(c1, c2);
6433         }
6434         var d = ++key;
6435         for(var i = 0; i < len1; i++){
6436             c1[i]._qdiff = d;
6437         }
6438         var r = [];
6439         for(var i = 0, len = c2.length; i < len; i++){
6440             if(c2[i]._qdiff != d){
6441                 r[r.length] = c2[i];
6442             }
6443         }
6444         return r;
6445     }
6446
6447     function quickId(ns, mode, root, id){
6448         if(ns == root){
6449            var d = root.ownerDocument || root;
6450            return d.getElementById(id);
6451         }
6452         ns = getNodes(ns, mode, "*");
6453         return byId(ns, null, id);
6454     }
6455
6456     return {
6457         getStyle : function(el, name){
6458             return Roo.fly(el).getStyle(name);
6459         },
6460         /**
6461          * Compiles a selector/xpath query into a reusable function. The returned function
6462          * takes one parameter "root" (optional), which is the context node from where the query should start.
6463          * @param {String} selector The selector/xpath query
6464          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
6465          * @return {Function}
6466          */
6467         compile : function(path, type){
6468             type = type || "select";
6469             
6470             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
6471             var q = path, mode, lq;
6472             var tk = Roo.DomQuery.matchers;
6473             var tklen = tk.length;
6474             var mm;
6475
6476             // accept leading mode switch
6477             var lmode = q.match(modeRe);
6478             if(lmode && lmode[1]){
6479                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
6480                 q = q.replace(lmode[1], "");
6481             }
6482             // strip leading slashes
6483             while(path.substr(0, 1)=="/"){
6484                 path = path.substr(1);
6485             }
6486
6487             while(q && lq != q){
6488                 lq = q;
6489                 var tm = q.match(tagTokenRe);
6490                 if(type == "select"){
6491                     if(tm){
6492                         if(tm[1] == "#"){
6493                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
6494                         }else{
6495                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
6496                         }
6497                         q = q.replace(tm[0], "");
6498                     }else if(q.substr(0, 1) != '@'){
6499                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
6500                     }
6501                 }else{
6502                     if(tm){
6503                         if(tm[1] == "#"){
6504                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
6505                         }else{
6506                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
6507                         }
6508                         q = q.replace(tm[0], "");
6509                     }
6510                 }
6511                 while(!(mm = q.match(modeRe))){
6512                     var matched = false;
6513                     for(var j = 0; j < tklen; j++){
6514                         var t = tk[j];
6515                         var m = q.match(t.re);
6516                         if(m){
6517                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
6518                                                     return m[i];
6519                                                 });
6520                             q = q.replace(m[0], "");
6521                             matched = true;
6522                             break;
6523                         }
6524                     }
6525                     // prevent infinite loop on bad selector
6526                     if(!matched){
6527                         throw 'Error parsing selector, parsing failed at "' + q + '"';
6528                     }
6529                 }
6530                 if(mm[1]){
6531                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
6532                     q = q.replace(mm[1], "");
6533                 }
6534             }
6535             fn[fn.length] = "return nodup(n);\n}";
6536             
6537              /** 
6538               * list of variables that need from compression as they are used by eval.
6539              *  eval:var:batch 
6540              *  eval:var:nodup
6541              *  eval:var:byTag
6542              *  eval:var:ById
6543              *  eval:var:getNodes
6544              *  eval:var:quickId
6545              *  eval:var:mode
6546              *  eval:var:root
6547              *  eval:var:n
6548              *  eval:var:byClassName
6549              *  eval:var:byPseudo
6550              *  eval:var:byAttribute
6551              *  eval:var:attrValue
6552              * 
6553              **/ 
6554             eval(fn.join(""));
6555             return f;
6556         },
6557
6558         /**
6559          * Selects a group of elements.
6560          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
6561          * @param {Node} root (optional) The start of the query (defaults to document).
6562          * @return {Array}
6563          */
6564         select : function(path, root, type){
6565             if(!root || root == document){
6566                 root = document;
6567             }
6568             if(typeof root == "string"){
6569                 root = document.getElementById(root);
6570             }
6571             var paths = path.split(",");
6572             var results = [];
6573             for(var i = 0, len = paths.length; i < len; i++){
6574                 var p = paths[i].replace(trimRe, "");
6575                 if(!cache[p]){
6576                     cache[p] = Roo.DomQuery.compile(p);
6577                     if(!cache[p]){
6578                         throw p + " is not a valid selector";
6579                     }
6580                 }
6581                 var result = cache[p](root);
6582                 if(result && result != document){
6583                     results = results.concat(result);
6584                 }
6585             }
6586             if(paths.length > 1){
6587                 return nodup(results);
6588             }
6589             return results;
6590         },
6591
6592         /**
6593          * Selects a single element.
6594          * @param {String} selector The selector/xpath query
6595          * @param {Node} root (optional) The start of the query (defaults to document).
6596          * @return {Element}
6597          */
6598         selectNode : function(path, root){
6599             return Roo.DomQuery.select(path, root)[0];
6600         },
6601
6602         /**
6603          * Selects the value of a node, optionally replacing null with the defaultValue.
6604          * @param {String} selector The selector/xpath query
6605          * @param {Node} root (optional) The start of the query (defaults to document).
6606          * @param {String} defaultValue
6607          */
6608         selectValue : function(path, root, defaultValue){
6609             path = path.replace(trimRe, "");
6610             if(!valueCache[path]){
6611                 valueCache[path] = Roo.DomQuery.compile(path, "select");
6612             }
6613             var n = valueCache[path](root);
6614             n = n[0] ? n[0] : n;
6615             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
6616             return ((v === null||v === undefined||v==='') ? defaultValue : v);
6617         },
6618
6619         /**
6620          * Selects the value of a node, parsing integers and floats.
6621          * @param {String} selector The selector/xpath query
6622          * @param {Node} root (optional) The start of the query (defaults to document).
6623          * @param {Number} defaultValue
6624          * @return {Number}
6625          */
6626         selectNumber : function(path, root, defaultValue){
6627             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
6628             return parseFloat(v);
6629         },
6630
6631         /**
6632          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
6633          * @param {String/HTMLElement/Array} el An element id, element or array of elements
6634          * @param {String} selector The simple selector to test
6635          * @return {Boolean}
6636          */
6637         is : function(el, ss){
6638             if(typeof el == "string"){
6639                 el = document.getElementById(el);
6640             }
6641             var isArray = (el instanceof Array);
6642             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
6643             return isArray ? (result.length == el.length) : (result.length > 0);
6644         },
6645
6646         /**
6647          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
6648          * @param {Array} el An array of elements to filter
6649          * @param {String} selector The simple selector to test
6650          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
6651          * the selector instead of the ones that match
6652          * @return {Array}
6653          */
6654         filter : function(els, ss, nonMatches){
6655             ss = ss.replace(trimRe, "");
6656             if(!simpleCache[ss]){
6657                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
6658             }
6659             var result = simpleCache[ss](els);
6660             return nonMatches ? quickDiff(result, els) : result;
6661         },
6662
6663         /**
6664          * Collection of matching regular expressions and code snippets.
6665          */
6666         matchers : [{
6667                 re: /^\.([\w-]+)/,
6668                 select: 'n = byClassName(n, null, " {1} ");'
6669             }, {
6670                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
6671                 select: 'n = byPseudo(n, "{1}", "{2}");'
6672             },{
6673                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
6674                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
6675             }, {
6676                 re: /^#([\w-]+)/,
6677                 select: 'n = byId(n, null, "{1}");'
6678             },{
6679                 re: /^@([\w-]+)/,
6680                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
6681             }
6682         ],
6683
6684         /**
6685          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
6686          * 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;.
6687          */
6688         operators : {
6689             "=" : function(a, v){
6690                 return a == v;
6691             },
6692             "!=" : function(a, v){
6693                 return a != v;
6694             },
6695             "^=" : function(a, v){
6696                 return a && a.substr(0, v.length) == v;
6697             },
6698             "$=" : function(a, v){
6699                 return a && a.substr(a.length-v.length) == v;
6700             },
6701             "*=" : function(a, v){
6702                 return a && a.indexOf(v) !== -1;
6703             },
6704             "%=" : function(a, v){
6705                 return (a % v) == 0;
6706             },
6707             "|=" : function(a, v){
6708                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
6709             },
6710             "~=" : function(a, v){
6711                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
6712             }
6713         },
6714
6715         /**
6716          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
6717          * and the argument (if any) supplied in the selector.
6718          */
6719         pseudos : {
6720             "first-child" : function(c){
6721                 var r = [], ri = -1, n;
6722                 for(var i = 0, ci; ci = n = c[i]; i++){
6723                     while((n = n.previousSibling) && n.nodeType != 1);
6724                     if(!n){
6725                         r[++ri] = ci;
6726                     }
6727                 }
6728                 return r;
6729             },
6730
6731             "last-child" : function(c){
6732                 var r = [], ri = -1, n;
6733                 for(var i = 0, ci; ci = n = c[i]; i++){
6734                     while((n = n.nextSibling) && n.nodeType != 1);
6735                     if(!n){
6736                         r[++ri] = ci;
6737                     }
6738                 }
6739                 return r;
6740             },
6741
6742             "nth-child" : function(c, a) {
6743                 var r = [], ri = -1;
6744                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
6745                 var f = (m[1] || 1) - 0, l = m[2] - 0;
6746                 for(var i = 0, n; n = c[i]; i++){
6747                     var pn = n.parentNode;
6748                     if (batch != pn._batch) {
6749                         var j = 0;
6750                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
6751                             if(cn.nodeType == 1){
6752                                cn.nodeIndex = ++j;
6753                             }
6754                         }
6755                         pn._batch = batch;
6756                     }
6757                     if (f == 1) {
6758                         if (l == 0 || n.nodeIndex == l){
6759                             r[++ri] = n;
6760                         }
6761                     } else if ((n.nodeIndex + l) % f == 0){
6762                         r[++ri] = n;
6763                     }
6764                 }
6765
6766                 return r;
6767             },
6768
6769             "only-child" : function(c){
6770                 var r = [], ri = -1;;
6771                 for(var i = 0, ci; ci = c[i]; i++){
6772                     if(!prev(ci) && !next(ci)){
6773                         r[++ri] = ci;
6774                     }
6775                 }
6776                 return r;
6777             },
6778
6779             "empty" : function(c){
6780                 var r = [], ri = -1;
6781                 for(var i = 0, ci; ci = c[i]; i++){
6782                     var cns = ci.childNodes, j = 0, cn, empty = true;
6783                     while(cn = cns[j]){
6784                         ++j;
6785                         if(cn.nodeType == 1 || cn.nodeType == 3){
6786                             empty = false;
6787                             break;
6788                         }
6789                     }
6790                     if(empty){
6791                         r[++ri] = ci;
6792                     }
6793                 }
6794                 return r;
6795             },
6796
6797             "contains" : function(c, v){
6798                 var r = [], ri = -1;
6799                 for(var i = 0, ci; ci = c[i]; i++){
6800                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
6801                         r[++ri] = ci;
6802                     }
6803                 }
6804                 return r;
6805             },
6806
6807             "nodeValue" : function(c, v){
6808                 var r = [], ri = -1;
6809                 for(var i = 0, ci; ci = c[i]; i++){
6810                     if(ci.firstChild && ci.firstChild.nodeValue == v){
6811                         r[++ri] = ci;
6812                     }
6813                 }
6814                 return r;
6815             },
6816
6817             "checked" : function(c){
6818                 var r = [], ri = -1;
6819                 for(var i = 0, ci; ci = c[i]; i++){
6820                     if(ci.checked == true){
6821                         r[++ri] = ci;
6822                     }
6823                 }
6824                 return r;
6825             },
6826
6827             "not" : function(c, ss){
6828                 return Roo.DomQuery.filter(c, ss, true);
6829             },
6830
6831             "odd" : function(c){
6832                 return this["nth-child"](c, "odd");
6833             },
6834
6835             "even" : function(c){
6836                 return this["nth-child"](c, "even");
6837             },
6838
6839             "nth" : function(c, a){
6840                 return c[a-1] || [];
6841             },
6842
6843             "first" : function(c){
6844                 return c[0] || [];
6845             },
6846
6847             "last" : function(c){
6848                 return c[c.length-1] || [];
6849             },
6850
6851             "has" : function(c, ss){
6852                 var s = Roo.DomQuery.select;
6853                 var r = [], ri = -1;
6854                 for(var i = 0, ci; ci = c[i]; i++){
6855                     if(s(ss, ci).length > 0){
6856                         r[++ri] = ci;
6857                     }
6858                 }
6859                 return r;
6860             },
6861
6862             "next" : function(c, ss){
6863                 var is = Roo.DomQuery.is;
6864                 var r = [], ri = -1;
6865                 for(var i = 0, ci; ci = c[i]; i++){
6866                     var n = next(ci);
6867                     if(n && is(n, ss)){
6868                         r[++ri] = ci;
6869                     }
6870                 }
6871                 return r;
6872             },
6873
6874             "prev" : function(c, ss){
6875                 var is = Roo.DomQuery.is;
6876                 var r = [], ri = -1;
6877                 for(var i = 0, ci; ci = c[i]; i++){
6878                     var n = prev(ci);
6879                     if(n && is(n, ss)){
6880                         r[++ri] = ci;
6881                     }
6882                 }
6883                 return r;
6884             }
6885         }
6886     };
6887 }();
6888
6889 /**
6890  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
6891  * @param {String} path The selector/xpath query
6892  * @param {Node} root (optional) The start of the query (defaults to document).
6893  * @return {Array}
6894  * @member Roo
6895  * @method query
6896  */
6897 Roo.query = Roo.DomQuery.select;
6898 /*
6899  * Based on:
6900  * Ext JS Library 1.1.1
6901  * Copyright(c) 2006-2007, Ext JS, LLC.
6902  *
6903  * Originally Released Under LGPL - original licence link has changed is not relivant.
6904  *
6905  * Fork - LGPL
6906  * <script type="text/javascript">
6907  */
6908
6909 /**
6910  * @class Roo.util.Observable
6911  * Base class that provides a common interface for publishing events. Subclasses are expected to
6912  * to have a property "events" with all the events defined.<br>
6913  * For example:
6914  * <pre><code>
6915  Employee = function(name){
6916     this.name = name;
6917     this.addEvents({
6918         "fired" : true,
6919         "quit" : true
6920     });
6921  }
6922  Roo.extend(Employee, Roo.util.Observable);
6923 </code></pre>
6924  * @param {Object} config properties to use (incuding events / listeners)
6925  */
6926
6927 Roo.util.Observable = function(cfg){
6928     
6929     cfg = cfg|| {};
6930     this.addEvents(cfg.events || {});
6931     if (cfg.events) {
6932         delete cfg.events; // make sure
6933     }
6934      
6935     Roo.apply(this, cfg);
6936     
6937     if(this.listeners){
6938         this.on(this.listeners);
6939         delete this.listeners;
6940     }
6941 };
6942 Roo.util.Observable.prototype = {
6943     /** 
6944  * @cfg {Object} listeners  list of events and functions to call for this object, 
6945  * For example :
6946  * <pre><code>
6947     listeners :  { 
6948        'click' : function(e) {
6949            ..... 
6950         } ,
6951         .... 
6952     } 
6953   </code></pre>
6954  */
6955     
6956     
6957     /**
6958      * Fires the specified event with the passed parameters (minus the event name).
6959      * @param {String} eventName
6960      * @param {Object...} args Variable number of parameters are passed to handlers
6961      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
6962      */
6963     fireEvent : function(){
6964         var ce = this.events[arguments[0].toLowerCase()];
6965         if(typeof ce == "object"){
6966             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
6967         }else{
6968             return true;
6969         }
6970     },
6971
6972     // private
6973     filterOptRe : /^(?:scope|delay|buffer|single)$/,
6974
6975     /**
6976      * Appends an event handler to this component
6977      * @param {String}   eventName The type of event to listen for
6978      * @param {Function} handler The method the event invokes
6979      * @param {Object}   scope (optional) The scope in which to execute the handler
6980      * function. The handler function's "this" context.
6981      * @param {Object}   options (optional) An object containing handler configuration
6982      * properties. This may contain any of the following properties:<ul>
6983      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6984      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6985      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6986      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6987      * by the specified number of milliseconds. If the event fires again within that time, the original
6988      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6989      * </ul><br>
6990      * <p>
6991      * <b>Combining Options</b><br>
6992      * Using the options argument, it is possible to combine different types of listeners:<br>
6993      * <br>
6994      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
6995                 <pre><code>
6996                 el.on('click', this.onClick, this, {
6997                         single: true,
6998                 delay: 100,
6999                 forumId: 4
7000                 });
7001                 </code></pre>
7002      * <p>
7003      * <b>Attaching multiple handlers in 1 call</b><br>
7004      * The method also allows for a single argument to be passed which is a config object containing properties
7005      * which specify multiple handlers.
7006      * <pre><code>
7007                 el.on({
7008                         'click': {
7009                         fn: this.onClick,
7010                         scope: this,
7011                         delay: 100
7012                 }, 
7013                 'mouseover': {
7014                         fn: this.onMouseOver,
7015                         scope: this
7016                 },
7017                 'mouseout': {
7018                         fn: this.onMouseOut,
7019                         scope: this
7020                 }
7021                 });
7022                 </code></pre>
7023      * <p>
7024      * Or a shorthand syntax which passes the same scope object to all handlers:
7025         <pre><code>
7026                 el.on({
7027                         'click': this.onClick,
7028                 'mouseover': this.onMouseOver,
7029                 'mouseout': this.onMouseOut,
7030                 scope: this
7031                 });
7032                 </code></pre>
7033      */
7034     addListener : function(eventName, fn, scope, o){
7035         if(typeof eventName == "object"){
7036             o = eventName;
7037             for(var e in o){
7038                 if(this.filterOptRe.test(e)){
7039                     continue;
7040                 }
7041                 if(typeof o[e] == "function"){
7042                     // shared options
7043                     this.addListener(e, o[e], o.scope,  o);
7044                 }else{
7045                     // individual options
7046                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
7047                 }
7048             }
7049             return;
7050         }
7051         o = (!o || typeof o == "boolean") ? {} : o;
7052         eventName = eventName.toLowerCase();
7053         var ce = this.events[eventName] || true;
7054         if(typeof ce == "boolean"){
7055             ce = new Roo.util.Event(this, eventName);
7056             this.events[eventName] = ce;
7057         }
7058         ce.addListener(fn, scope, o);
7059     },
7060
7061     /**
7062      * Removes a listener
7063      * @param {String}   eventName     The type of event to listen for
7064      * @param {Function} handler        The handler to remove
7065      * @param {Object}   scope  (optional) The scope (this object) for the handler
7066      */
7067     removeListener : function(eventName, fn, scope){
7068         var ce = this.events[eventName.toLowerCase()];
7069         if(typeof ce == "object"){
7070             ce.removeListener(fn, scope);
7071         }
7072     },
7073
7074     /**
7075      * Removes all listeners for this object
7076      */
7077     purgeListeners : function(){
7078         for(var evt in this.events){
7079             if(typeof this.events[evt] == "object"){
7080                  this.events[evt].clearListeners();
7081             }
7082         }
7083     },
7084
7085     relayEvents : function(o, events){
7086         var createHandler = function(ename){
7087             return function(){
7088                  
7089                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
7090             };
7091         };
7092         for(var i = 0, len = events.length; i < len; i++){
7093             var ename = events[i];
7094             if(!this.events[ename]){
7095                 this.events[ename] = true;
7096             };
7097             o.on(ename, createHandler(ename), this);
7098         }
7099     },
7100
7101     /**
7102      * Used to define events on this Observable
7103      * @param {Object} object The object with the events defined
7104      */
7105     addEvents : function(o){
7106         if(!this.events){
7107             this.events = {};
7108         }
7109         Roo.applyIf(this.events, o);
7110     },
7111
7112     /**
7113      * Checks to see if this object has any listeners for a specified event
7114      * @param {String} eventName The name of the event to check for
7115      * @return {Boolean} True if the event is being listened for, else false
7116      */
7117     hasListener : function(eventName){
7118         var e = this.events[eventName];
7119         return typeof e == "object" && e.listeners.length > 0;
7120     }
7121 };
7122 /**
7123  * Appends an event handler to this element (shorthand for addListener)
7124  * @param {String}   eventName     The type of event to listen for
7125  * @param {Function} handler        The method the event invokes
7126  * @param {Object}   scope (optional) The scope in which to execute the handler
7127  * function. The handler function's "this" context.
7128  * @param {Object}   options  (optional)
7129  * @method
7130  */
7131 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
7132 /**
7133  * Removes a listener (shorthand for removeListener)
7134  * @param {String}   eventName     The type of event to listen for
7135  * @param {Function} handler        The handler to remove
7136  * @param {Object}   scope  (optional) The scope (this object) for the handler
7137  * @method
7138  */
7139 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
7140
7141 /**
7142  * Starts capture on the specified Observable. All events will be passed
7143  * to the supplied function with the event name + standard signature of the event
7144  * <b>before</b> the event is fired. If the supplied function returns false,
7145  * the event will not fire.
7146  * @param {Observable} o The Observable to capture
7147  * @param {Function} fn The function to call
7148  * @param {Object} scope (optional) The scope (this object) for the fn
7149  * @static
7150  */
7151 Roo.util.Observable.capture = function(o, fn, scope){
7152     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
7153 };
7154
7155 /**
7156  * Removes <b>all</b> added captures from the Observable.
7157  * @param {Observable} o The Observable to release
7158  * @static
7159  */
7160 Roo.util.Observable.releaseCapture = function(o){
7161     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
7162 };
7163
7164 (function(){
7165
7166     var createBuffered = function(h, o, scope){
7167         var task = new Roo.util.DelayedTask();
7168         return function(){
7169             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
7170         };
7171     };
7172
7173     var createSingle = function(h, e, fn, scope){
7174         return function(){
7175             e.removeListener(fn, scope);
7176             return h.apply(scope, arguments);
7177         };
7178     };
7179
7180     var createDelayed = function(h, o, scope){
7181         return function(){
7182             var args = Array.prototype.slice.call(arguments, 0);
7183             setTimeout(function(){
7184                 h.apply(scope, args);
7185             }, o.delay || 10);
7186         };
7187     };
7188
7189     Roo.util.Event = function(obj, name){
7190         this.name = name;
7191         this.obj = obj;
7192         this.listeners = [];
7193     };
7194
7195     Roo.util.Event.prototype = {
7196         addListener : function(fn, scope, options){
7197             var o = options || {};
7198             scope = scope || this.obj;
7199             if(!this.isListening(fn, scope)){
7200                 var l = {fn: fn, scope: scope, options: o};
7201                 var h = fn;
7202                 if(o.delay){
7203                     h = createDelayed(h, o, scope);
7204                 }
7205                 if(o.single){
7206                     h = createSingle(h, this, fn, scope);
7207                 }
7208                 if(o.buffer){
7209                     h = createBuffered(h, o, scope);
7210                 }
7211                 l.fireFn = h;
7212                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
7213                     this.listeners.push(l);
7214                 }else{
7215                     this.listeners = this.listeners.slice(0);
7216                     this.listeners.push(l);
7217                 }
7218             }
7219         },
7220
7221         findListener : function(fn, scope){
7222             scope = scope || this.obj;
7223             var ls = this.listeners;
7224             for(var i = 0, len = ls.length; i < len; i++){
7225                 var l = ls[i];
7226                 if(l.fn == fn && l.scope == scope){
7227                     return i;
7228                 }
7229             }
7230             return -1;
7231         },
7232
7233         isListening : function(fn, scope){
7234             return this.findListener(fn, scope) != -1;
7235         },
7236
7237         removeListener : function(fn, scope){
7238             var index;
7239             if((index = this.findListener(fn, scope)) != -1){
7240                 if(!this.firing){
7241                     this.listeners.splice(index, 1);
7242                 }else{
7243                     this.listeners = this.listeners.slice(0);
7244                     this.listeners.splice(index, 1);
7245                 }
7246                 return true;
7247             }
7248             return false;
7249         },
7250
7251         clearListeners : function(){
7252             this.listeners = [];
7253         },
7254
7255         fire : function(){
7256             var ls = this.listeners, scope, len = ls.length;
7257             if(len > 0){
7258                 this.firing = true;
7259                 var args = Array.prototype.slice.call(arguments, 0);                
7260                 for(var i = 0; i < len; i++){
7261                     var l = ls[i];
7262                     if(l.fireFn.apply(l.scope||this.obj||window, args) === false){
7263                         this.firing = false;
7264                         return false;
7265                     }
7266                 }
7267                 this.firing = false;
7268             }
7269             return true;
7270         }
7271     };
7272 })();/*
7273  * RooJS Library 
7274  * Copyright(c) 2007-2017, Roo J Solutions Ltd
7275  *
7276  * Licence LGPL 
7277  *
7278  */
7279  
7280 /**
7281  * @class Roo.Document
7282  * @extends Roo.util.Observable
7283  * This is a convience class to wrap up the main document loading code.. , rather than adding Roo.onReady(......)
7284  * 
7285  * @param {Object} config the methods and properties of the 'base' class for the application.
7286  * 
7287  *  Generic Page handler - implement this to start your app..
7288  * 
7289  * eg.
7290  *  MyProject = new Roo.Document({
7291         events : {
7292             'load' : true // your events..
7293         },
7294         listeners : {
7295             'ready' : function() {
7296                 // fired on Roo.onReady()
7297             }
7298         }
7299  * 
7300  */
7301 Roo.Document = function(cfg) {
7302      
7303     this.addEvents({ 
7304         'ready' : true
7305     });
7306     Roo.util.Observable.call(this,cfg);
7307     
7308     var _this = this;
7309     
7310     Roo.onReady(function() {
7311         _this.fireEvent('ready');
7312     },null,false);
7313     
7314     
7315 }
7316
7317 Roo.extend(Roo.Document, Roo.util.Observable, {});/*
7318  * Based on:
7319  * Ext JS Library 1.1.1
7320  * Copyright(c) 2006-2007, Ext JS, LLC.
7321  *
7322  * Originally Released Under LGPL - original licence link has changed is not relivant.
7323  *
7324  * Fork - LGPL
7325  * <script type="text/javascript">
7326  */
7327
7328 /**
7329  * @class Roo.EventManager
7330  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
7331  * several useful events directly.
7332  * See {@link Roo.EventObject} for more details on normalized event objects.
7333  * @static
7334  */
7335 Roo.EventManager = function(){
7336     var docReadyEvent, docReadyProcId, docReadyState = false;
7337     var resizeEvent, resizeTask, textEvent, textSize;
7338     var E = Roo.lib.Event;
7339     var D = Roo.lib.Dom;
7340
7341     
7342     
7343
7344     var fireDocReady = function(){
7345         if(!docReadyState){
7346             docReadyState = true;
7347             Roo.isReady = true;
7348             if(docReadyProcId){
7349                 clearInterval(docReadyProcId);
7350             }
7351             if(Roo.isGecko || Roo.isOpera) {
7352                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
7353             }
7354             if(Roo.isIE){
7355                 var defer = document.getElementById("ie-deferred-loader");
7356                 if(defer){
7357                     defer.onreadystatechange = null;
7358                     defer.parentNode.removeChild(defer);
7359                 }
7360             }
7361             if(docReadyEvent){
7362                 docReadyEvent.fire();
7363                 docReadyEvent.clearListeners();
7364             }
7365         }
7366     };
7367     
7368     var initDocReady = function(){
7369         docReadyEvent = new Roo.util.Event();
7370         if(Roo.isGecko || Roo.isOpera) {
7371             document.addEventListener("DOMContentLoaded", fireDocReady, false);
7372         }else if(Roo.isIE){
7373             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
7374             var defer = document.getElementById("ie-deferred-loader");
7375             defer.onreadystatechange = function(){
7376                 if(this.readyState == "complete"){
7377                     fireDocReady();
7378                 }
7379             };
7380         }else if(Roo.isSafari){ 
7381             docReadyProcId = setInterval(function(){
7382                 var rs = document.readyState;
7383                 if(rs == "complete") {
7384                     fireDocReady();     
7385                  }
7386             }, 10);
7387         }
7388         // no matter what, make sure it fires on load
7389         E.on(window, "load", fireDocReady);
7390     };
7391
7392     var createBuffered = function(h, o){
7393         var task = new Roo.util.DelayedTask(h);
7394         return function(e){
7395             // create new event object impl so new events don't wipe out properties
7396             e = new Roo.EventObjectImpl(e);
7397             task.delay(o.buffer, h, null, [e]);
7398         };
7399     };
7400
7401     var createSingle = function(h, el, ename, fn){
7402         return function(e){
7403             Roo.EventManager.removeListener(el, ename, fn);
7404             h(e);
7405         };
7406     };
7407
7408     var createDelayed = function(h, o){
7409         return function(e){
7410             // create new event object impl so new events don't wipe out properties
7411             e = new Roo.EventObjectImpl(e);
7412             setTimeout(function(){
7413                 h(e);
7414             }, o.delay || 10);
7415         };
7416     };
7417     var transitionEndVal = false;
7418     
7419     var transitionEnd = function()
7420     {
7421         if (transitionEndVal) {
7422             return transitionEndVal;
7423         }
7424         var el = document.createElement('div');
7425
7426         var transEndEventNames = {
7427             WebkitTransition : 'webkitTransitionEnd',
7428             MozTransition    : 'transitionend',
7429             OTransition      : 'oTransitionEnd otransitionend',
7430             transition       : 'transitionend'
7431         };
7432     
7433         for (var name in transEndEventNames) {
7434             if (el.style[name] !== undefined) {
7435                 transitionEndVal = transEndEventNames[name];
7436                 return  transitionEndVal ;
7437             }
7438         }
7439     }
7440     
7441   
7442
7443     var listen = function(element, ename, opt, fn, scope)
7444     {
7445         var o = (!opt || typeof opt == "boolean") ? {} : opt;
7446         fn = fn || o.fn; scope = scope || o.scope;
7447         var el = Roo.getDom(element);
7448         
7449         
7450         if(!el){
7451             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
7452         }
7453         
7454         if (ename == 'transitionend') {
7455             ename = transitionEnd();
7456         }
7457         var h = function(e){
7458             e = Roo.EventObject.setEvent(e);
7459             var t;
7460             if(o.delegate){
7461                 t = e.getTarget(o.delegate, el);
7462                 if(!t){
7463                     return;
7464                 }
7465             }else{
7466                 t = e.target;
7467             }
7468             if(o.stopEvent === true){
7469                 e.stopEvent();
7470             }
7471             if(o.preventDefault === true){
7472                e.preventDefault();
7473             }
7474             if(o.stopPropagation === true){
7475                 e.stopPropagation();
7476             }
7477
7478             if(o.normalized === false){
7479                 e = e.browserEvent;
7480             }
7481
7482             fn.call(scope || el, e, t, o);
7483         };
7484         if(o.delay){
7485             h = createDelayed(h, o);
7486         }
7487         if(o.single){
7488             h = createSingle(h, el, ename, fn);
7489         }
7490         if(o.buffer){
7491             h = createBuffered(h, o);
7492         }
7493         
7494         fn._handlers = fn._handlers || [];
7495         
7496         
7497         fn._handlers.push([Roo.id(el), ename, h]);
7498         
7499         
7500          
7501         E.on(el, ename, h); // this adds the actuall listener to the object..
7502         
7503         
7504         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
7505             el.addEventListener("DOMMouseScroll", h, false);
7506             E.on(window, 'unload', function(){
7507                 el.removeEventListener("DOMMouseScroll", h, false);
7508             });
7509         }
7510         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
7511             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
7512         }
7513         return h;
7514     };
7515
7516     var stopListening = function(el, ename, fn){
7517         var id = Roo.id(el), hds = fn._handlers, hd = fn;
7518         if(hds){
7519             for(var i = 0, len = hds.length; i < len; i++){
7520                 var h = hds[i];
7521                 if(h[0] == id && h[1] == ename){
7522                     hd = h[2];
7523                     hds.splice(i, 1);
7524                     break;
7525                 }
7526             }
7527         }
7528         E.un(el, ename, hd);
7529         el = Roo.getDom(el);
7530         if(ename == "mousewheel" && el.addEventListener){
7531             el.removeEventListener("DOMMouseScroll", hd, false);
7532         }
7533         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
7534             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
7535         }
7536     };
7537
7538     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
7539     
7540     var pub = {
7541         
7542         
7543         /** 
7544          * Fix for doc tools
7545          * @scope Roo.EventManager
7546          */
7547         
7548         
7549         /** 
7550          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
7551          * object with a Roo.EventObject
7552          * @param {Function} fn        The method the event invokes
7553          * @param {Object}   scope    An object that becomes the scope of the handler
7554          * @param {boolean}  override If true, the obj passed in becomes
7555          *                             the execution scope of the listener
7556          * @return {Function} The wrapped function
7557          * @deprecated
7558          */
7559         wrap : function(fn, scope, override){
7560             return function(e){
7561                 Roo.EventObject.setEvent(e);
7562                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
7563             };
7564         },
7565         
7566         /**
7567      * Appends an event handler to an element (shorthand for addListener)
7568      * @param {String/HTMLElement}   element        The html element or id to assign the
7569      * @param {String}   eventName The type of event to listen for
7570      * @param {Function} handler The method the event invokes
7571      * @param {Object}   scope (optional) The scope in which to execute the handler
7572      * function. The handler function's "this" context.
7573      * @param {Object}   options (optional) An object containing handler configuration
7574      * properties. This may contain any of the following properties:<ul>
7575      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
7576      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
7577      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
7578      * <li>preventDefault {Boolean} True to prevent the default action</li>
7579      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
7580      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
7581      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
7582      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
7583      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
7584      * by the specified number of milliseconds. If the event fires again within that time, the original
7585      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
7586      * </ul><br>
7587      * <p>
7588      * <b>Combining Options</b><br>
7589      * Using the options argument, it is possible to combine different types of listeners:<br>
7590      * <br>
7591      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
7592      * Code:<pre><code>
7593 el.on('click', this.onClick, this, {
7594     single: true,
7595     delay: 100,
7596     stopEvent : true,
7597     forumId: 4
7598 });</code></pre>
7599      * <p>
7600      * <b>Attaching multiple handlers in 1 call</b><br>
7601       * The method also allows for a single argument to be passed which is a config object containing properties
7602      * which specify multiple handlers.
7603      * <p>
7604      * Code:<pre><code>
7605 el.on({
7606     'click' : {
7607         fn: this.onClick
7608         scope: this,
7609         delay: 100
7610     },
7611     'mouseover' : {
7612         fn: this.onMouseOver
7613         scope: this
7614     },
7615     'mouseout' : {
7616         fn: this.onMouseOut
7617         scope: this
7618     }
7619 });</code></pre>
7620      * <p>
7621      * Or a shorthand syntax:<br>
7622      * Code:<pre><code>
7623 el.on({
7624     'click' : this.onClick,
7625     'mouseover' : this.onMouseOver,
7626     'mouseout' : this.onMouseOut
7627     scope: this
7628 });</code></pre>
7629      */
7630         addListener : function(element, eventName, fn, scope, options){
7631             if(typeof eventName == "object"){
7632                 var o = eventName;
7633                 for(var e in o){
7634                     if(propRe.test(e)){
7635                         continue;
7636                     }
7637                     if(typeof o[e] == "function"){
7638                         // shared options
7639                         listen(element, e, o, o[e], o.scope);
7640                     }else{
7641                         // individual options
7642                         listen(element, e, o[e]);
7643                     }
7644                 }
7645                 return;
7646             }
7647             return listen(element, eventName, options, fn, scope);
7648         },
7649         
7650         /**
7651          * Removes an event handler
7652          *
7653          * @param {String/HTMLElement}   element        The id or html element to remove the 
7654          *                             event from
7655          * @param {String}   eventName     The type of event
7656          * @param {Function} fn
7657          * @return {Boolean} True if a listener was actually removed
7658          */
7659         removeListener : function(element, eventName, fn){
7660             return stopListening(element, eventName, fn);
7661         },
7662         
7663         /**
7664          * Fires when the document is ready (before onload and before images are loaded). Can be 
7665          * accessed shorthanded Roo.onReady().
7666          * @param {Function} fn        The method the event invokes
7667          * @param {Object}   scope    An  object that becomes the scope of the handler
7668          * @param {boolean}  options
7669          */
7670         onDocumentReady : function(fn, scope, options){
7671             if(docReadyState){ // if it already fired
7672                 docReadyEvent.addListener(fn, scope, options);
7673                 docReadyEvent.fire();
7674                 docReadyEvent.clearListeners();
7675                 return;
7676             }
7677             if(!docReadyEvent){
7678                 initDocReady();
7679             }
7680             docReadyEvent.addListener(fn, scope, options);
7681         },
7682         
7683         /**
7684          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
7685          * @param {Function} fn        The method the event invokes
7686          * @param {Object}   scope    An object that becomes the scope of the handler
7687          * @param {boolean}  options
7688          */
7689         onWindowResize : function(fn, scope, options)
7690         {
7691             if(!resizeEvent){
7692                 resizeEvent = new Roo.util.Event();
7693                 resizeTask = new Roo.util.DelayedTask(function(){
7694                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
7695                 });
7696                 E.on(window, "resize", function()
7697                 {
7698                     if (Roo.isIE) {
7699                         resizeTask.delay(50);
7700                     } else {
7701                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
7702                     }
7703                 });
7704             }
7705             resizeEvent.addListener(fn, scope, options);
7706         },
7707
7708         /**
7709          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
7710          * @param {Function} fn        The method the event invokes
7711          * @param {Object}   scope    An object that becomes the scope of the handler
7712          * @param {boolean}  options
7713          */
7714         onTextResize : function(fn, scope, options){
7715             if(!textEvent){
7716                 textEvent = new Roo.util.Event();
7717                 var textEl = new Roo.Element(document.createElement('div'));
7718                 textEl.dom.className = 'x-text-resize';
7719                 textEl.dom.innerHTML = 'X';
7720                 textEl.appendTo(document.body);
7721                 textSize = textEl.dom.offsetHeight;
7722                 setInterval(function(){
7723                     if(textEl.dom.offsetHeight != textSize){
7724                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
7725                     }
7726                 }, this.textResizeInterval);
7727             }
7728             textEvent.addListener(fn, scope, options);
7729         },
7730
7731         /**
7732          * Removes the passed window resize listener.
7733          * @param {Function} fn        The method the event invokes
7734          * @param {Object}   scope    The scope of handler
7735          */
7736         removeResizeListener : function(fn, scope){
7737             if(resizeEvent){
7738                 resizeEvent.removeListener(fn, scope);
7739             }
7740         },
7741
7742         // private
7743         fireResize : function(){
7744             if(resizeEvent){
7745                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
7746             }   
7747         },
7748         /**
7749          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
7750          */
7751         ieDeferSrc : false,
7752         /**
7753          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
7754          */
7755         textResizeInterval : 50
7756     };
7757     
7758     /**
7759      * Fix for doc tools
7760      * @scopeAlias pub=Roo.EventManager
7761      */
7762     
7763      /**
7764      * Appends an event handler to an element (shorthand for addListener)
7765      * @param {String/HTMLElement}   element        The html element or id to assign the
7766      * @param {String}   eventName The type of event to listen for
7767      * @param {Function} handler The method the event invokes
7768      * @param {Object}   scope (optional) The scope in which to execute the handler
7769      * function. The handler function's "this" context.
7770      * @param {Object}   options (optional) An object containing handler configuration
7771      * properties. This may contain any of the following properties:<ul>
7772      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
7773      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
7774      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
7775      * <li>preventDefault {Boolean} True to prevent the default action</li>
7776      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
7777      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
7778      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
7779      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
7780      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
7781      * by the specified number of milliseconds. If the event fires again within that time, the original
7782      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
7783      * </ul><br>
7784      * <p>
7785      * <b>Combining Options</b><br>
7786      * Using the options argument, it is possible to combine different types of listeners:<br>
7787      * <br>
7788      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
7789      * Code:<pre><code>
7790 el.on('click', this.onClick, this, {
7791     single: true,
7792     delay: 100,
7793     stopEvent : true,
7794     forumId: 4
7795 });</code></pre>
7796      * <p>
7797      * <b>Attaching multiple handlers in 1 call</b><br>
7798       * The method also allows for a single argument to be passed which is a config object containing properties
7799      * which specify multiple handlers.
7800      * <p>
7801      * Code:<pre><code>
7802 el.on({
7803     'click' : {
7804         fn: this.onClick
7805         scope: this,
7806         delay: 100
7807     },
7808     'mouseover' : {
7809         fn: this.onMouseOver
7810         scope: this
7811     },
7812     'mouseout' : {
7813         fn: this.onMouseOut
7814         scope: this
7815     }
7816 });</code></pre>
7817      * <p>
7818      * Or a shorthand syntax:<br>
7819      * Code:<pre><code>
7820 el.on({
7821     'click' : this.onClick,
7822     'mouseover' : this.onMouseOver,
7823     'mouseout' : this.onMouseOut
7824     scope: this
7825 });</code></pre>
7826      */
7827     pub.on = pub.addListener;
7828     pub.un = pub.removeListener;
7829
7830     pub.stoppedMouseDownEvent = new Roo.util.Event();
7831     return pub;
7832 }();
7833 /**
7834   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
7835   * @param {Function} fn        The method the event invokes
7836   * @param {Object}   scope    An  object that becomes the scope of the handler
7837   * @param {boolean}  override If true, the obj passed in becomes
7838   *                             the execution scope of the listener
7839   * @member Roo
7840   * @method onReady
7841  */
7842 Roo.onReady = Roo.EventManager.onDocumentReady;
7843
7844 Roo.onReady(function(){
7845     var bd = Roo.get(document.body);
7846     if(!bd){ return; }
7847
7848     var cls = [
7849             Roo.isIE ? "roo-ie"
7850             : Roo.isIE11 ? "roo-ie11"
7851             : Roo.isEdge ? "roo-edge"
7852             : Roo.isGecko ? "roo-gecko"
7853             : Roo.isOpera ? "roo-opera"
7854             : Roo.isSafari ? "roo-safari" : ""];
7855
7856     if(Roo.isMac){
7857         cls.push("roo-mac");
7858     }
7859     if(Roo.isLinux){
7860         cls.push("roo-linux");
7861     }
7862     if(Roo.isIOS){
7863         cls.push("roo-ios");
7864     }
7865     if(Roo.isTouch){
7866         cls.push("roo-touch");
7867     }
7868     if(Roo.isBorderBox){
7869         cls.push('roo-border-box');
7870     }
7871     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
7872         var p = bd.dom.parentNode;
7873         if(p){
7874             p.className += ' roo-strict';
7875         }
7876     }
7877     bd.addClass(cls.join(' '));
7878 });
7879
7880 /**
7881  * @class Roo.EventObject
7882  * EventObject exposes the Yahoo! UI Event functionality directly on the object
7883  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
7884  * Example:
7885  * <pre><code>
7886  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
7887     e.preventDefault();
7888     var target = e.getTarget();
7889     ...
7890  }
7891  var myDiv = Roo.get("myDiv");
7892  myDiv.on("click", handleClick);
7893  //or
7894  Roo.EventManager.on("myDiv", 'click', handleClick);
7895  Roo.EventManager.addListener("myDiv", 'click', handleClick);
7896  </code></pre>
7897  * @static
7898  */
7899 Roo.EventObject = function(){
7900     
7901     var E = Roo.lib.Event;
7902     
7903     // safari keypress events for special keys return bad keycodes
7904     var safariKeys = {
7905         63234 : 37, // left
7906         63235 : 39, // right
7907         63232 : 38, // up
7908         63233 : 40, // down
7909         63276 : 33, // page up
7910         63277 : 34, // page down
7911         63272 : 46, // delete
7912         63273 : 36, // home
7913         63275 : 35  // end
7914     };
7915
7916     // normalize button clicks
7917     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
7918                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
7919
7920     Roo.EventObjectImpl = function(e){
7921         if(e){
7922             this.setEvent(e.browserEvent || e);
7923         }
7924     };
7925     Roo.EventObjectImpl.prototype = {
7926         /**
7927          * Used to fix doc tools.
7928          * @scope Roo.EventObject.prototype
7929          */
7930             
7931
7932         
7933         
7934         /** The normal browser event */
7935         browserEvent : null,
7936         /** The button pressed in a mouse event */
7937         button : -1,
7938         /** True if the shift key was down during the event */
7939         shiftKey : false,
7940         /** True if the control key was down during the event */
7941         ctrlKey : false,
7942         /** True if the alt key was down during the event */
7943         altKey : false,
7944
7945         /** Key constant 
7946         * @type Number */
7947         BACKSPACE : 8,
7948         /** Key constant 
7949         * @type Number */
7950         TAB : 9,
7951         /** Key constant 
7952         * @type Number */
7953         RETURN : 13,
7954         /** Key constant 
7955         * @type Number */
7956         ENTER : 13,
7957         /** Key constant 
7958         * @type Number */
7959         SHIFT : 16,
7960         /** Key constant 
7961         * @type Number */
7962         CONTROL : 17,
7963         /** Key constant 
7964         * @type Number */
7965         ESC : 27,
7966         /** Key constant 
7967         * @type Number */
7968         SPACE : 32,
7969         /** Key constant 
7970         * @type Number */
7971         PAGEUP : 33,
7972         /** Key constant 
7973         * @type Number */
7974         PAGEDOWN : 34,
7975         /** Key constant 
7976         * @type Number */
7977         END : 35,
7978         /** Key constant 
7979         * @type Number */
7980         HOME : 36,
7981         /** Key constant 
7982         * @type Number */
7983         LEFT : 37,
7984         /** Key constant 
7985         * @type Number */
7986         UP : 38,
7987         /** Key constant 
7988         * @type Number */
7989         RIGHT : 39,
7990         /** Key constant 
7991         * @type Number */
7992         DOWN : 40,
7993         /** Key constant 
7994         * @type Number */
7995         DELETE : 46,
7996         /** Key constant 
7997         * @type Number */
7998         F5 : 116,
7999
8000            /** @private */
8001         setEvent : function(e){
8002             if(e == this || (e && e.browserEvent)){ // already wrapped
8003                 return e;
8004             }
8005             this.browserEvent = e;
8006             if(e){
8007                 // normalize buttons
8008                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
8009                 if(e.type == 'click' && this.button == -1){
8010                     this.button = 0;
8011                 }
8012                 this.type = e.type;
8013                 this.shiftKey = e.shiftKey;
8014                 // mac metaKey behaves like ctrlKey
8015                 this.ctrlKey = e.ctrlKey || e.metaKey;
8016                 this.altKey = e.altKey;
8017                 // in getKey these will be normalized for the mac
8018                 this.keyCode = e.keyCode;
8019                 // keyup warnings on firefox.
8020                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
8021                 // cache the target for the delayed and or buffered events
8022                 this.target = E.getTarget(e);
8023                 // same for XY
8024                 this.xy = E.getXY(e);
8025             }else{
8026                 this.button = -1;
8027                 this.shiftKey = false;
8028                 this.ctrlKey = false;
8029                 this.altKey = false;
8030                 this.keyCode = 0;
8031                 this.charCode =0;
8032                 this.target = null;
8033                 this.xy = [0, 0];
8034             }
8035             return this;
8036         },
8037
8038         /**
8039          * Stop the event (preventDefault and stopPropagation)
8040          */
8041         stopEvent : function(){
8042             if(this.browserEvent){
8043                 if(this.browserEvent.type == 'mousedown'){
8044                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
8045                 }
8046                 E.stopEvent(this.browserEvent);
8047             }
8048         },
8049
8050         /**
8051          * Prevents the browsers default handling of the event.
8052          */
8053         preventDefault : function(){
8054             if(this.browserEvent){
8055                 E.preventDefault(this.browserEvent);
8056             }
8057         },
8058
8059         /** @private */
8060         isNavKeyPress : function(){
8061             var k = this.keyCode;
8062             k = Roo.isSafari ? (safariKeys[k] || k) : k;
8063             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
8064         },
8065
8066         isSpecialKey : function(){
8067             var k = this.keyCode;
8068             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
8069             (k == 16) || (k == 17) ||
8070             (k >= 18 && k <= 20) ||
8071             (k >= 33 && k <= 35) ||
8072             (k >= 36 && k <= 39) ||
8073             (k >= 44 && k <= 45);
8074         },
8075         /**
8076          * Cancels bubbling of the event.
8077          */
8078         stopPropagation : function(){
8079             if(this.browserEvent){
8080                 if(this.type == 'mousedown'){
8081                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
8082                 }
8083                 E.stopPropagation(this.browserEvent);
8084             }
8085         },
8086
8087         /**
8088          * Gets the key code for the event.
8089          * @return {Number}
8090          */
8091         getCharCode : function(){
8092             return this.charCode || this.keyCode;
8093         },
8094
8095         /**
8096          * Returns a normalized keyCode for the event.
8097          * @return {Number} The key code
8098          */
8099         getKey : function(){
8100             var k = this.keyCode || this.charCode;
8101             return Roo.isSafari ? (safariKeys[k] || k) : k;
8102         },
8103
8104         /**
8105          * Gets the x coordinate of the event.
8106          * @return {Number}
8107          */
8108         getPageX : function(){
8109             return this.xy[0];
8110         },
8111
8112         /**
8113          * Gets the y coordinate of the event.
8114          * @return {Number}
8115          */
8116         getPageY : function(){
8117             return this.xy[1];
8118         },
8119
8120         /**
8121          * Gets the time of the event.
8122          * @return {Number}
8123          */
8124         getTime : function(){
8125             if(this.browserEvent){
8126                 return E.getTime(this.browserEvent);
8127             }
8128             return null;
8129         },
8130
8131         /**
8132          * Gets the page coordinates of the event.
8133          * @return {Array} The xy values like [x, y]
8134          */
8135         getXY : function(){
8136             return this.xy;
8137         },
8138
8139         /**
8140          * Gets the target for the event.
8141          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
8142          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8143                 search as a number or element (defaults to 10 || document.body)
8144          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
8145          * @return {HTMLelement}
8146          */
8147         getTarget : function(selector, maxDepth, returnEl){
8148             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
8149         },
8150         /**
8151          * Gets the related target.
8152          * @return {HTMLElement}
8153          */
8154         getRelatedTarget : function(){
8155             if(this.browserEvent){
8156                 return E.getRelatedTarget(this.browserEvent);
8157             }
8158             return null;
8159         },
8160
8161         /**
8162          * Normalizes mouse wheel delta across browsers
8163          * @return {Number} The delta
8164          */
8165         getWheelDelta : function(){
8166             var e = this.browserEvent;
8167             var delta = 0;
8168             if(e.wheelDelta){ /* IE/Opera. */
8169                 delta = e.wheelDelta/120;
8170             }else if(e.detail){ /* Mozilla case. */
8171                 delta = -e.detail/3;
8172             }
8173             return delta;
8174         },
8175
8176         /**
8177          * Returns true if the control, meta, shift or alt key was pressed during this event.
8178          * @return {Boolean}
8179          */
8180         hasModifier : function(){
8181             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
8182         },
8183
8184         /**
8185          * Returns true if the target of this event equals el or is a child of el
8186          * @param {String/HTMLElement/Element} el
8187          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
8188          * @return {Boolean}
8189          */
8190         within : function(el, related){
8191             var t = this[related ? "getRelatedTarget" : "getTarget"]();
8192             return t && Roo.fly(el).contains(t);
8193         },
8194
8195         getPoint : function(){
8196             return new Roo.lib.Point(this.xy[0], this.xy[1]);
8197         }
8198     };
8199
8200     return new Roo.EventObjectImpl();
8201 }();
8202             
8203     /*
8204  * Based on:
8205  * Ext JS Library 1.1.1
8206  * Copyright(c) 2006-2007, Ext JS, LLC.
8207  *
8208  * Originally Released Under LGPL - original licence link has changed is not relivant.
8209  *
8210  * Fork - LGPL
8211  * <script type="text/javascript">
8212  */
8213
8214  
8215 // was in Composite Element!??!?!
8216  
8217 (function(){
8218     var D = Roo.lib.Dom;
8219     var E = Roo.lib.Event;
8220     var A = Roo.lib.Anim;
8221
8222     // local style camelizing for speed
8223     var propCache = {};
8224     var camelRe = /(-[a-z])/gi;
8225     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
8226     var view = document.defaultView;
8227
8228 /**
8229  * @class Roo.Element
8230  * Represents an Element in the DOM.<br><br>
8231  * Usage:<br>
8232 <pre><code>
8233 var el = Roo.get("my-div");
8234
8235 // or with getEl
8236 var el = getEl("my-div");
8237
8238 // or with a DOM element
8239 var el = Roo.get(myDivElement);
8240 </code></pre>
8241  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
8242  * each call instead of constructing a new one.<br><br>
8243  * <b>Animations</b><br />
8244  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
8245  * should either be a boolean (true) or an object literal with animation options. The animation options are:
8246 <pre>
8247 Option    Default   Description
8248 --------- --------  ---------------------------------------------
8249 duration  .35       The duration of the animation in seconds
8250 easing    easeOut   The YUI easing method
8251 callback  none      A function to execute when the anim completes
8252 scope     this      The scope (this) of the callback function
8253 </pre>
8254 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
8255 * manipulate the animation. Here's an example:
8256 <pre><code>
8257 var el = Roo.get("my-div");
8258
8259 // no animation
8260 el.setWidth(100);
8261
8262 // default animation
8263 el.setWidth(100, true);
8264
8265 // animation with some options set
8266 el.setWidth(100, {
8267     duration: 1,
8268     callback: this.foo,
8269     scope: this
8270 });
8271
8272 // using the "anim" property to get the Anim object
8273 var opt = {
8274     duration: 1,
8275     callback: this.foo,
8276     scope: this
8277 };
8278 el.setWidth(100, opt);
8279 ...
8280 if(opt.anim.isAnimated()){
8281     opt.anim.stop();
8282 }
8283 </code></pre>
8284 * <b> Composite (Collections of) Elements</b><br />
8285  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
8286  * @constructor Create a new Element directly.
8287  * @param {String/HTMLElement} element
8288  * @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).
8289  */
8290     Roo.Element = function(element, forceNew)
8291     {
8292         var dom = typeof element == "string" ?
8293                 document.getElementById(element) : element;
8294         
8295         this.listeners = {};
8296         
8297         if(!dom){ // invalid id/element
8298             return null;
8299         }
8300         var id = dom.id;
8301         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
8302             return Roo.Element.cache[id];
8303         }
8304
8305         /**
8306          * The DOM element
8307          * @type HTMLElement
8308          */
8309         this.dom = dom;
8310
8311         /**
8312          * The DOM element ID
8313          * @type String
8314          */
8315         this.id = id || Roo.id(dom);
8316         
8317         return this; // assumed for cctor?
8318     };
8319
8320     var El = Roo.Element;
8321
8322     El.prototype = {
8323         /**
8324          * The element's default display mode  (defaults to "") 
8325          * @type String
8326          */
8327         originalDisplay : "",
8328
8329         
8330         // note this is overridden in BS version..
8331         visibilityMode : 1, 
8332         /**
8333          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
8334          * @type String
8335          */
8336         defaultUnit : "px",
8337         
8338         /**
8339          * Sets the element's visibility mode. When setVisible() is called it
8340          * will use this to determine whether to set the visibility or the display property.
8341          * @param visMode Element.VISIBILITY or Element.DISPLAY
8342          * @return {Roo.Element} this
8343          */
8344         setVisibilityMode : function(visMode){
8345             this.visibilityMode = visMode;
8346             return this;
8347         },
8348         /**
8349          * Convenience method for setVisibilityMode(Element.DISPLAY)
8350          * @param {String} display (optional) What to set display to when visible
8351          * @return {Roo.Element} this
8352          */
8353         enableDisplayMode : function(display){
8354             this.setVisibilityMode(El.DISPLAY);
8355             if(typeof display != "undefined") { this.originalDisplay = display; }
8356             return this;
8357         },
8358
8359         /**
8360          * 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)
8361          * @param {String} selector The simple selector to test
8362          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8363                 search as a number or element (defaults to 10 || document.body)
8364          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
8365          * @return {HTMLElement} The matching DOM node (or null if no match was found)
8366          */
8367         findParent : function(simpleSelector, maxDepth, returnEl){
8368             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
8369             maxDepth = maxDepth || 50;
8370             if(typeof maxDepth != "number"){
8371                 stopEl = Roo.getDom(maxDepth);
8372                 maxDepth = 10;
8373             }
8374             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
8375                 if(dq.is(p, simpleSelector)){
8376                     return returnEl ? Roo.get(p) : p;
8377                 }
8378                 depth++;
8379                 p = p.parentNode;
8380             }
8381             return null;
8382         },
8383
8384
8385         /**
8386          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
8387          * @param {String} selector The simple selector to test
8388          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8389                 search as a number or element (defaults to 10 || document.body)
8390          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
8391          * @return {HTMLElement} The matching DOM node (or null if no match was found)
8392          */
8393         findParentNode : function(simpleSelector, maxDepth, returnEl){
8394             var p = Roo.fly(this.dom.parentNode, '_internal');
8395             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
8396         },
8397         
8398         /**
8399          * Looks at  the scrollable parent element
8400          */
8401         findScrollableParent : function()
8402         {
8403             var overflowRegex = /(auto|scroll)/;
8404             
8405             if(this.getStyle('position') === 'fixed'){
8406                 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
8407             }
8408             
8409             var excludeStaticParent = this.getStyle('position') === "absolute";
8410             
8411             for (var parent = this; (parent = Roo.get(parent.dom.parentNode));){
8412                 
8413                 if (excludeStaticParent && parent.getStyle('position') === "static") {
8414                     continue;
8415                 }
8416                 
8417                 if (overflowRegex.test(parent.getStyle('overflow') + parent.getStyle('overflow-x') + parent.getStyle('overflow-y'))){
8418                     return parent;
8419                 }
8420                 
8421                 if(parent.dom.nodeName.toLowerCase() == 'body'){
8422                     return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
8423                 }
8424             }
8425             
8426             return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
8427         },
8428
8429         /**
8430          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
8431          * This is a shortcut for findParentNode() that always returns an Roo.Element.
8432          * @param {String} selector The simple selector to test
8433          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8434                 search as a number or element (defaults to 10 || document.body)
8435          * @return {Roo.Element} The matching DOM node (or null if no match was found)
8436          */
8437         up : function(simpleSelector, maxDepth){
8438             return this.findParentNode(simpleSelector, maxDepth, true);
8439         },
8440
8441
8442
8443         /**
8444          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
8445          * @param {String} selector The simple selector to test
8446          * @return {Boolean} True if this element matches the selector, else false
8447          */
8448         is : function(simpleSelector){
8449             return Roo.DomQuery.is(this.dom, simpleSelector);
8450         },
8451
8452         /**
8453          * Perform animation on this element.
8454          * @param {Object} args The YUI animation control args
8455          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
8456          * @param {Function} onComplete (optional) Function to call when animation completes
8457          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
8458          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
8459          * @return {Roo.Element} this
8460          */
8461         animate : function(args, duration, onComplete, easing, animType){
8462             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
8463             return this;
8464         },
8465
8466         /*
8467          * @private Internal animation call
8468          */
8469         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
8470             animType = animType || 'run';
8471             opt = opt || {};
8472             var anim = Roo.lib.Anim[animType](
8473                 this.dom, args,
8474                 (opt.duration || defaultDur) || .35,
8475                 (opt.easing || defaultEase) || 'easeOut',
8476                 function(){
8477                     Roo.callback(cb, this);
8478                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
8479                 },
8480                 this
8481             );
8482             opt.anim = anim;
8483             return anim;
8484         },
8485
8486         // private legacy anim prep
8487         preanim : function(a, i){
8488             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
8489         },
8490
8491         /**
8492          * Removes worthless text nodes
8493          * @param {Boolean} forceReclean (optional) By default the element
8494          * keeps track if it has been cleaned already so
8495          * you can call this over and over. However, if you update the element and
8496          * need to force a reclean, you can pass true.
8497          */
8498         clean : function(forceReclean){
8499             if(this.isCleaned && forceReclean !== true){
8500                 return this;
8501             }
8502             var ns = /\S/;
8503             var d = this.dom, n = d.firstChild, ni = -1;
8504             while(n){
8505                 var nx = n.nextSibling;
8506                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
8507                     d.removeChild(n);
8508                 }else{
8509                     n.nodeIndex = ++ni;
8510                 }
8511                 n = nx;
8512             }
8513             this.isCleaned = true;
8514             return this;
8515         },
8516
8517         // private
8518         calcOffsetsTo : function(el){
8519             el = Roo.get(el);
8520             var d = el.dom;
8521             var restorePos = false;
8522             if(el.getStyle('position') == 'static'){
8523                 el.position('relative');
8524                 restorePos = true;
8525             }
8526             var x = 0, y =0;
8527             var op = this.dom;
8528             while(op && op != d && op.tagName != 'HTML'){
8529                 x+= op.offsetLeft;
8530                 y+= op.offsetTop;
8531                 op = op.offsetParent;
8532             }
8533             if(restorePos){
8534                 el.position('static');
8535             }
8536             return [x, y];
8537         },
8538
8539         /**
8540          * Scrolls this element into view within the passed container.
8541          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
8542          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
8543          * @return {Roo.Element} this
8544          */
8545         scrollIntoView : function(container, hscroll){
8546             var c = Roo.getDom(container) || document.body;
8547             var el = this.dom;
8548
8549             var o = this.calcOffsetsTo(c),
8550                 l = o[0],
8551                 t = o[1],
8552                 b = t+el.offsetHeight,
8553                 r = l+el.offsetWidth;
8554
8555             var ch = c.clientHeight;
8556             var ct = parseInt(c.scrollTop, 10);
8557             var cl = parseInt(c.scrollLeft, 10);
8558             var cb = ct + ch;
8559             var cr = cl + c.clientWidth;
8560
8561             if(t < ct){
8562                 c.scrollTop = t;
8563             }else if(b > cb){
8564                 c.scrollTop = b-ch;
8565             }
8566
8567             if(hscroll !== false){
8568                 if(l < cl){
8569                     c.scrollLeft = l;
8570                 }else if(r > cr){
8571                     c.scrollLeft = r-c.clientWidth;
8572                 }
8573             }
8574             return this;
8575         },
8576
8577         // private
8578         scrollChildIntoView : function(child, hscroll){
8579             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
8580         },
8581
8582         /**
8583          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
8584          * the new height may not be available immediately.
8585          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
8586          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
8587          * @param {Function} onComplete (optional) Function to call when animation completes
8588          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
8589          * @return {Roo.Element} this
8590          */
8591         autoHeight : function(animate, duration, onComplete, easing){
8592             var oldHeight = this.getHeight();
8593             this.clip();
8594             this.setHeight(1); // force clipping
8595             setTimeout(function(){
8596                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
8597                 if(!animate){
8598                     this.setHeight(height);
8599                     this.unclip();
8600                     if(typeof onComplete == "function"){
8601                         onComplete();
8602                     }
8603                 }else{
8604                     this.setHeight(oldHeight); // restore original height
8605                     this.setHeight(height, animate, duration, function(){
8606                         this.unclip();
8607                         if(typeof onComplete == "function") { onComplete(); }
8608                     }.createDelegate(this), easing);
8609                 }
8610             }.createDelegate(this), 0);
8611             return this;
8612         },
8613
8614         /**
8615          * Returns true if this element is an ancestor of the passed element
8616          * @param {HTMLElement/String} el The element to check
8617          * @return {Boolean} True if this element is an ancestor of el, else false
8618          */
8619         contains : function(el){
8620             if(!el){return false;}
8621             return D.isAncestor(this.dom, el.dom ? el.dom : el);
8622         },
8623
8624         /**
8625          * Checks whether the element is currently visible using both visibility and display properties.
8626          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
8627          * @return {Boolean} True if the element is currently visible, else false
8628          */
8629         isVisible : function(deep) {
8630             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
8631             if(deep !== true || !vis){
8632                 return vis;
8633             }
8634             var p = this.dom.parentNode;
8635             while(p && p.tagName.toLowerCase() != "body"){
8636                 if(!Roo.fly(p, '_isVisible').isVisible()){
8637                     return false;
8638                 }
8639                 p = p.parentNode;
8640             }
8641             return true;
8642         },
8643
8644         /**
8645          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
8646          * @param {String} selector The CSS selector
8647          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
8648          * @return {CompositeElement/CompositeElementLite} The composite element
8649          */
8650         select : function(selector, unique){
8651             return El.select(selector, unique, this.dom);
8652         },
8653
8654         /**
8655          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
8656          * @param {String} selector The CSS selector
8657          * @return {Array} An array of the matched nodes
8658          */
8659         query : function(selector, unique){
8660             return Roo.DomQuery.select(selector, this.dom);
8661         },
8662
8663         /**
8664          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
8665          * @param {String} selector The CSS selector
8666          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
8667          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
8668          */
8669         child : function(selector, returnDom){
8670             var n = Roo.DomQuery.selectNode(selector, this.dom);
8671             return returnDom ? n : Roo.get(n);
8672         },
8673
8674         /**
8675          * Selects a single *direct* child 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         down : function(selector, returnDom){
8681             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
8682             return returnDom ? n : Roo.get(n);
8683         },
8684
8685         /**
8686          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
8687          * @param {String} group The group the DD object is member of
8688          * @param {Object} config The DD config object
8689          * @param {Object} overrides An object containing methods to override/implement on the DD object
8690          * @return {Roo.dd.DD} The DD object
8691          */
8692         initDD : function(group, config, overrides){
8693             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
8694             return Roo.apply(dd, overrides);
8695         },
8696
8697         /**
8698          * Initializes a {@link Roo.dd.DDProxy} object for this element.
8699          * @param {String} group The group the DDProxy object is member of
8700          * @param {Object} config The DDProxy config object
8701          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
8702          * @return {Roo.dd.DDProxy} The DDProxy object
8703          */
8704         initDDProxy : function(group, config, overrides){
8705             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
8706             return Roo.apply(dd, overrides);
8707         },
8708
8709         /**
8710          * Initializes a {@link Roo.dd.DDTarget} object for this element.
8711          * @param {String} group The group the DDTarget object is member of
8712          * @param {Object} config The DDTarget config object
8713          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
8714          * @return {Roo.dd.DDTarget} The DDTarget object
8715          */
8716         initDDTarget : function(group, config, overrides){
8717             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
8718             return Roo.apply(dd, overrides);
8719         },
8720
8721         /**
8722          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
8723          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
8724          * @param {Boolean} visible Whether the element is visible
8725          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8726          * @return {Roo.Element} this
8727          */
8728          setVisible : function(visible, animate){
8729             if(!animate || !A){
8730                 if(this.visibilityMode == El.DISPLAY){
8731                     this.setDisplayed(visible);
8732                 }else{
8733                     this.fixDisplay();
8734                     this.dom.style.visibility = visible ? "visible" : "hidden";
8735                 }
8736             }else{
8737                 // closure for composites
8738                 var dom = this.dom;
8739                 var visMode = this.visibilityMode;
8740                 if(visible){
8741                     this.setOpacity(.01);
8742                     this.setVisible(true);
8743                 }
8744                 this.anim({opacity: { to: (visible?1:0) }},
8745                       this.preanim(arguments, 1),
8746                       null, .35, 'easeIn', function(){
8747                          if(!visible){
8748                              if(visMode == El.DISPLAY){
8749                                  dom.style.display = "none";
8750                              }else{
8751                                  dom.style.visibility = "hidden";
8752                              }
8753                              Roo.get(dom).setOpacity(1);
8754                          }
8755                      });
8756             }
8757             return this;
8758         },
8759
8760         /**
8761          * Returns true if display is not "none"
8762          * @return {Boolean}
8763          */
8764         isDisplayed : function() {
8765             return this.getStyle("display") != "none";
8766         },
8767
8768         /**
8769          * Toggles the element's visibility or display, depending on visibility mode.
8770          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8771          * @return {Roo.Element} this
8772          */
8773         toggle : function(animate){
8774             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
8775             return this;
8776         },
8777
8778         /**
8779          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
8780          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
8781          * @return {Roo.Element} this
8782          */
8783         setDisplayed : function(value) {
8784             if(typeof value == "boolean"){
8785                value = value ? this.originalDisplay : "none";
8786             }
8787             this.setStyle("display", value);
8788             return this;
8789         },
8790
8791         /**
8792          * Tries to focus the element. Any exceptions are caught and ignored.
8793          * @return {Roo.Element} this
8794          */
8795         focus : function() {
8796             try{
8797                 this.dom.focus();
8798             }catch(e){}
8799             return this;
8800         },
8801
8802         /**
8803          * Tries to blur the element. Any exceptions are caught and ignored.
8804          * @return {Roo.Element} this
8805          */
8806         blur : function() {
8807             try{
8808                 this.dom.blur();
8809             }catch(e){}
8810             return this;
8811         },
8812
8813         /**
8814          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
8815          * @param {String/Array} className The CSS class to add, or an array of classes
8816          * @return {Roo.Element} this
8817          */
8818         addClass : function(className){
8819             if(className instanceof Array){
8820                 for(var i = 0, len = className.length; i < len; i++) {
8821                     this.addClass(className[i]);
8822                 }
8823             }else{
8824                 if(className && !this.hasClass(className)){
8825                     if (this.dom instanceof SVGElement) {
8826                         this.dom.className.baseVal =this.dom.className.baseVal  + " " + className;
8827                     } else {
8828                         this.dom.className = this.dom.className + " " + className;
8829                     }
8830                 }
8831             }
8832             return this;
8833         },
8834
8835         /**
8836          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
8837          * @param {String/Array} className The CSS class to add, or an array of classes
8838          * @return {Roo.Element} this
8839          */
8840         radioClass : function(className){
8841             var siblings = this.dom.parentNode.childNodes;
8842             for(var i = 0; i < siblings.length; i++) {
8843                 var s = siblings[i];
8844                 if(s.nodeType == 1){
8845                     Roo.get(s).removeClass(className);
8846                 }
8847             }
8848             this.addClass(className);
8849             return this;
8850         },
8851
8852         /**
8853          * Removes one or more CSS classes from the element.
8854          * @param {String/Array} className The CSS class to remove, or an array of classes
8855          * @return {Roo.Element} this
8856          */
8857         removeClass : function(className){
8858             
8859             var cn = this.dom instanceof SVGElement ? this.dom.className.baseVal : this.dom.className;
8860             if(!className || !cn){
8861                 return this;
8862             }
8863             if(className instanceof Array){
8864                 for(var i = 0, len = className.length; i < len; i++) {
8865                     this.removeClass(className[i]);
8866                 }
8867             }else{
8868                 if(this.hasClass(className)){
8869                     var re = this.classReCache[className];
8870                     if (!re) {
8871                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
8872                        this.classReCache[className] = re;
8873                     }
8874                     if (this.dom instanceof SVGElement) {
8875                         this.dom.className.baseVal = cn.replace(re, " ");
8876                     } else {
8877                         this.dom.className = cn.replace(re, " ");
8878                     }
8879                 }
8880             }
8881             return this;
8882         },
8883
8884         // private
8885         classReCache: {},
8886
8887         /**
8888          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
8889          * @param {String} className The CSS class to toggle
8890          * @return {Roo.Element} this
8891          */
8892         toggleClass : function(className){
8893             if(this.hasClass(className)){
8894                 this.removeClass(className);
8895             }else{
8896                 this.addClass(className);
8897             }
8898             return this;
8899         },
8900
8901         /**
8902          * Checks if the specified CSS class exists on this element's DOM node.
8903          * @param {String} className The CSS class to check for
8904          * @return {Boolean} True if the class exists, else false
8905          */
8906         hasClass : function(className){
8907             if (this.dom instanceof SVGElement) {
8908                 return className && (' '+this.dom.className.baseVal +' ').indexOf(' '+className+' ') != -1; 
8909             } 
8910             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
8911         },
8912
8913         /**
8914          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
8915          * @param {String} oldClassName The CSS class to replace
8916          * @param {String} newClassName The replacement CSS class
8917          * @return {Roo.Element} this
8918          */
8919         replaceClass : function(oldClassName, newClassName){
8920             this.removeClass(oldClassName);
8921             this.addClass(newClassName);
8922             return this;
8923         },
8924
8925         /**
8926          * Returns an object with properties matching the styles requested.
8927          * For example, el.getStyles('color', 'font-size', 'width') might return
8928          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
8929          * @param {String} style1 A style name
8930          * @param {String} style2 A style name
8931          * @param {String} etc.
8932          * @return {Object} The style object
8933          */
8934         getStyles : function(){
8935             var a = arguments, len = a.length, r = {};
8936             for(var i = 0; i < len; i++){
8937                 r[a[i]] = this.getStyle(a[i]);
8938             }
8939             return r;
8940         },
8941
8942         /**
8943          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
8944          * @param {String} property The style property whose value is returned.
8945          * @return {String} The current value of the style property for this element.
8946          */
8947         getStyle : function(){
8948             return view && view.getComputedStyle ?
8949                 function(prop){
8950                     var el = this.dom, v, cs, camel;
8951                     if(prop == 'float'){
8952                         prop = "cssFloat";
8953                     }
8954                     if(el.style && (v = el.style[prop])){
8955                         return v;
8956                     }
8957                     if(cs = view.getComputedStyle(el, "")){
8958                         if(!(camel = propCache[prop])){
8959                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
8960                         }
8961                         return cs[camel];
8962                     }
8963                     return null;
8964                 } :
8965                 function(prop){
8966                     var el = this.dom, v, cs, camel;
8967                     if(prop == 'opacity'){
8968                         if(typeof el.style.filter == 'string'){
8969                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
8970                             if(m){
8971                                 var fv = parseFloat(m[1]);
8972                                 if(!isNaN(fv)){
8973                                     return fv ? fv / 100 : 0;
8974                                 }
8975                             }
8976                         }
8977                         return 1;
8978                     }else if(prop == 'float'){
8979                         prop = "styleFloat";
8980                     }
8981                     if(!(camel = propCache[prop])){
8982                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
8983                     }
8984                     if(v = el.style[camel]){
8985                         return v;
8986                     }
8987                     if(cs = el.currentStyle){
8988                         return cs[camel];
8989                     }
8990                     return null;
8991                 };
8992         }(),
8993
8994         /**
8995          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
8996          * @param {String/Object} property The style property to be set, or an object of multiple styles.
8997          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
8998          * @return {Roo.Element} this
8999          */
9000         setStyle : function(prop, value){
9001             if(typeof prop == "string"){
9002                 
9003                 if (prop == 'float') {
9004                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
9005                     return this;
9006                 }
9007                 
9008                 var camel;
9009                 if(!(camel = propCache[prop])){
9010                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
9011                 }
9012                 
9013                 if(camel == 'opacity') {
9014                     this.setOpacity(value);
9015                 }else{
9016                     this.dom.style[camel] = value;
9017                 }
9018             }else{
9019                 for(var style in prop){
9020                     if(typeof prop[style] != "function"){
9021                        this.setStyle(style, prop[style]);
9022                     }
9023                 }
9024             }
9025             return this;
9026         },
9027
9028         /**
9029          * More flexible version of {@link #setStyle} for setting style properties.
9030          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
9031          * a function which returns such a specification.
9032          * @return {Roo.Element} this
9033          */
9034         applyStyles : function(style){
9035             Roo.DomHelper.applyStyles(this.dom, style);
9036             return this;
9037         },
9038
9039         /**
9040           * 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).
9041           * @return {Number} The X position of the element
9042           */
9043         getX : function(){
9044             return D.getX(this.dom);
9045         },
9046
9047         /**
9048           * 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).
9049           * @return {Number} The Y position of the element
9050           */
9051         getY : function(){
9052             return D.getY(this.dom);
9053         },
9054
9055         /**
9056           * 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).
9057           * @return {Array} The XY position of the element
9058           */
9059         getXY : function(){
9060             return D.getXY(this.dom);
9061         },
9062
9063         /**
9064          * 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).
9065          * @param {Number} The X position of the element
9066          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
9067          * @return {Roo.Element} this
9068          */
9069         setX : function(x, animate){
9070             if(!animate || !A){
9071                 D.setX(this.dom, x);
9072             }else{
9073                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
9074             }
9075             return this;
9076         },
9077
9078         /**
9079          * 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).
9080          * @param {Number} The Y position of the element
9081          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
9082          * @return {Roo.Element} this
9083          */
9084         setY : function(y, animate){
9085             if(!animate || !A){
9086                 D.setY(this.dom, y);
9087             }else{
9088                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
9089             }
9090             return this;
9091         },
9092
9093         /**
9094          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
9095          * @param {String} left The left CSS property value
9096          * @return {Roo.Element} this
9097          */
9098         setLeft : function(left){
9099             this.setStyle("left", this.addUnits(left));
9100             return this;
9101         },
9102
9103         /**
9104          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
9105          * @param {String} top The top CSS property value
9106          * @return {Roo.Element} this
9107          */
9108         setTop : function(top){
9109             this.setStyle("top", this.addUnits(top));
9110             return this;
9111         },
9112
9113         /**
9114          * Sets the element's CSS right style.
9115          * @param {String} right The right CSS property value
9116          * @return {Roo.Element} this
9117          */
9118         setRight : function(right){
9119             this.setStyle("right", this.addUnits(right));
9120             return this;
9121         },
9122
9123         /**
9124          * Sets the element's CSS bottom style.
9125          * @param {String} bottom The bottom CSS property value
9126          * @return {Roo.Element} this
9127          */
9128         setBottom : function(bottom){
9129             this.setStyle("bottom", this.addUnits(bottom));
9130             return this;
9131         },
9132
9133         /**
9134          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
9135          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
9136          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
9137          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
9138          * @return {Roo.Element} this
9139          */
9140         setXY : function(pos, animate){
9141             if(!animate || !A){
9142                 D.setXY(this.dom, pos);
9143             }else{
9144                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
9145             }
9146             return this;
9147         },
9148
9149         /**
9150          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
9151          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
9152          * @param {Number} x X value for new position (coordinates are page-based)
9153          * @param {Number} y Y value for new position (coordinates are page-based)
9154          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
9155          * @return {Roo.Element} this
9156          */
9157         setLocation : function(x, y, animate){
9158             this.setXY([x, y], this.preanim(arguments, 2));
9159             return this;
9160         },
9161
9162         /**
9163          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
9164          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
9165          * @param {Number} x X value for new position (coordinates are page-based)
9166          * @param {Number} y Y value for new position (coordinates are page-based)
9167          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
9168          * @return {Roo.Element} this
9169          */
9170         moveTo : function(x, y, animate){
9171             this.setXY([x, y], this.preanim(arguments, 2));
9172             return this;
9173         },
9174
9175         /**
9176          * Returns the region of the given element.
9177          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
9178          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
9179          */
9180         getRegion : function(){
9181             return D.getRegion(this.dom);
9182         },
9183
9184         /**
9185          * Returns the offset height of the element
9186          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
9187          * @return {Number} The element's height
9188          */
9189         getHeight : function(contentHeight){
9190             var h = this.dom.offsetHeight || 0;
9191             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
9192         },
9193
9194         /**
9195          * Returns the offset width of the element
9196          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
9197          * @return {Number} The element's width
9198          */
9199         getWidth : function(contentWidth){
9200             var w = this.dom.offsetWidth || 0;
9201             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
9202         },
9203
9204         /**
9205          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
9206          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
9207          * if a height has not been set using CSS.
9208          * @return {Number}
9209          */
9210         getComputedHeight : function(){
9211             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
9212             if(!h){
9213                 h = parseInt(this.getStyle('height'), 10) || 0;
9214                 if(!this.isBorderBox()){
9215                     h += this.getFrameWidth('tb');
9216                 }
9217             }
9218             return h;
9219         },
9220
9221         /**
9222          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
9223          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
9224          * if a width has not been set using CSS.
9225          * @return {Number}
9226          */
9227         getComputedWidth : function(){
9228             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
9229             if(!w){
9230                 w = parseInt(this.getStyle('width'), 10) || 0;
9231                 if(!this.isBorderBox()){
9232                     w += this.getFrameWidth('lr');
9233                 }
9234             }
9235             return w;
9236         },
9237
9238         /**
9239          * Returns the size of the element.
9240          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
9241          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
9242          */
9243         getSize : function(contentSize){
9244             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
9245         },
9246
9247         /**
9248          * Returns the width and height of the viewport.
9249          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
9250          */
9251         getViewSize : function(){
9252             var d = this.dom, doc = document, aw = 0, ah = 0;
9253             if(d == doc || d == doc.body){
9254                 return {width : D.getViewWidth(), height: D.getViewHeight()};
9255             }else{
9256                 return {
9257                     width : d.clientWidth,
9258                     height: d.clientHeight
9259                 };
9260             }
9261         },
9262
9263         /**
9264          * Returns the value of the "value" attribute
9265          * @param {Boolean} asNumber true to parse the value as a number
9266          * @return {String/Number}
9267          */
9268         getValue : function(asNumber){
9269             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
9270         },
9271
9272         // private
9273         adjustWidth : function(width){
9274             if(typeof width == "number"){
9275                 if(this.autoBoxAdjust && !this.isBorderBox()){
9276                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
9277                 }
9278                 if(width < 0){
9279                     width = 0;
9280                 }
9281             }
9282             return width;
9283         },
9284
9285         // private
9286         adjustHeight : function(height){
9287             if(typeof height == "number"){
9288                if(this.autoBoxAdjust && !this.isBorderBox()){
9289                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
9290                }
9291                if(height < 0){
9292                    height = 0;
9293                }
9294             }
9295             return height;
9296         },
9297
9298         /**
9299          * Set the width of the element
9300          * @param {Number} width The new width
9301          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9302          * @return {Roo.Element} this
9303          */
9304         setWidth : function(width, animate){
9305             width = this.adjustWidth(width);
9306             if(!animate || !A){
9307                 this.dom.style.width = this.addUnits(width);
9308             }else{
9309                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
9310             }
9311             return this;
9312         },
9313
9314         /**
9315          * Set the height of the element
9316          * @param {Number} height The new height
9317          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9318          * @return {Roo.Element} this
9319          */
9320          setHeight : function(height, animate){
9321             height = this.adjustHeight(height);
9322             if(!animate || !A){
9323                 this.dom.style.height = this.addUnits(height);
9324             }else{
9325                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
9326             }
9327             return this;
9328         },
9329
9330         /**
9331          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
9332          * @param {Number} width The new width
9333          * @param {Number} height The new height
9334          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9335          * @return {Roo.Element} this
9336          */
9337          setSize : function(width, height, animate){
9338             if(typeof width == "object"){ // in case of object from getSize()
9339                 height = width.height; width = width.width;
9340             }
9341             width = this.adjustWidth(width); height = this.adjustHeight(height);
9342             if(!animate || !A){
9343                 this.dom.style.width = this.addUnits(width);
9344                 this.dom.style.height = this.addUnits(height);
9345             }else{
9346                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
9347             }
9348             return this;
9349         },
9350
9351         /**
9352          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
9353          * @param {Number} x X value for new position (coordinates are page-based)
9354          * @param {Number} y Y value for new position (coordinates are page-based)
9355          * @param {Number} width The new width
9356          * @param {Number} height The new height
9357          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9358          * @return {Roo.Element} this
9359          */
9360         setBounds : function(x, y, width, height, animate){
9361             if(!animate || !A){
9362                 this.setSize(width, height);
9363                 this.setLocation(x, y);
9364             }else{
9365                 width = this.adjustWidth(width); height = this.adjustHeight(height);
9366                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
9367                               this.preanim(arguments, 4), 'motion');
9368             }
9369             return this;
9370         },
9371
9372         /**
9373          * 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.
9374          * @param {Roo.lib.Region} region The region to fill
9375          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9376          * @return {Roo.Element} this
9377          */
9378         setRegion : function(region, animate){
9379             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
9380             return this;
9381         },
9382
9383         /**
9384          * Appends an event handler
9385          *
9386          * @param {String}   eventName     The type of event to append
9387          * @param {Function} fn        The method the event invokes
9388          * @param {Object} scope       (optional) The scope (this object) of the fn
9389          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9390          */
9391         addListener : function(eventName, fn, scope, options)
9392         {
9393             if (eventName == 'dblclick') { // doublclick (touchstart) - faked on touch.
9394                 this.addListener('touchstart', this.onTapHandler, this);
9395             }
9396             
9397             // we need to handle a special case where dom element is a svg element.
9398             // in this case we do not actua
9399             if (!this.dom) {
9400                 return;
9401             }
9402             
9403             if (this.dom instanceof SVGElement && !(this.dom instanceof SVGSVGElement)) {
9404                 if (typeof(this.listeners[eventName]) == 'undefined') {
9405                     this.listeners[eventName] =  new Roo.util.Event(this, eventName);
9406                 }
9407                 this.listeners[eventName].addListener(fn, scope, options);
9408                 return;
9409             }
9410             
9411                 
9412             Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
9413             
9414             
9415         },
9416         tapedTwice : false,
9417         onTapHandler : function(event)
9418         {
9419             if(!this.tapedTwice) {
9420                 this.tapedTwice = true;
9421                 var s = this;
9422                 setTimeout( function() {
9423                     s.tapedTwice = false;
9424                 }, 300 );
9425                 return;
9426             }
9427             event.preventDefault();
9428             var revent = new MouseEvent('dblclick',  {
9429                 view: window,
9430                 bubbles: true,
9431                 cancelable: true
9432             });
9433              
9434             this.dom.dispatchEvent(revent);
9435             //action on double tap goes below
9436              
9437         }, 
9438  
9439         /**
9440          * Removes an event handler from this element
9441          * @param {String} eventName the type of event to remove
9442          * @param {Function} fn the method the event invokes
9443          * @param {Function} scope (needed for svg fake listeners)
9444          * @return {Roo.Element} this
9445          */
9446         removeListener : function(eventName, fn, scope){
9447             Roo.EventManager.removeListener(this.dom,  eventName, fn);
9448             if (typeof(this.listeners) == 'undefined'  || typeof(this.listeners[eventName]) == 'undefined') {
9449                 return this;
9450             }
9451             this.listeners[eventName].removeListener(fn, scope);
9452             return this;
9453         },
9454
9455         /**
9456          * Removes all previous added listeners from this element
9457          * @return {Roo.Element} this
9458          */
9459         removeAllListeners : function(){
9460             E.purgeElement(this.dom);
9461             this.listeners = {};
9462             return this;
9463         },
9464
9465         relayEvent : function(eventName, observable){
9466             this.on(eventName, function(e){
9467                 observable.fireEvent(eventName, e);
9468             });
9469         },
9470
9471         
9472         /**
9473          * Set the opacity of the element
9474          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
9475          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9476          * @return {Roo.Element} this
9477          */
9478          setOpacity : function(opacity, animate){
9479             if(!animate || !A){
9480                 var s = this.dom.style;
9481                 if(Roo.isIE){
9482                     s.zoom = 1;
9483                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
9484                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
9485                 }else{
9486                     s.opacity = opacity;
9487                 }
9488             }else{
9489                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
9490             }
9491             return this;
9492         },
9493
9494         /**
9495          * Gets the left X coordinate
9496          * @param {Boolean} local True to get the local css position instead of page coordinate
9497          * @return {Number}
9498          */
9499         getLeft : function(local){
9500             if(!local){
9501                 return this.getX();
9502             }else{
9503                 return parseInt(this.getStyle("left"), 10) || 0;
9504             }
9505         },
9506
9507         /**
9508          * Gets the right X coordinate of the element (element X position + element width)
9509          * @param {Boolean} local True to get the local css position instead of page coordinate
9510          * @return {Number}
9511          */
9512         getRight : function(local){
9513             if(!local){
9514                 return this.getX() + this.getWidth();
9515             }else{
9516                 return (this.getLeft(true) + this.getWidth()) || 0;
9517             }
9518         },
9519
9520         /**
9521          * Gets the top Y coordinate
9522          * @param {Boolean} local True to get the local css position instead of page coordinate
9523          * @return {Number}
9524          */
9525         getTop : function(local) {
9526             if(!local){
9527                 return this.getY();
9528             }else{
9529                 return parseInt(this.getStyle("top"), 10) || 0;
9530             }
9531         },
9532
9533         /**
9534          * Gets the bottom Y coordinate of the element (element Y position + element height)
9535          * @param {Boolean} local True to get the local css position instead of page coordinate
9536          * @return {Number}
9537          */
9538         getBottom : function(local){
9539             if(!local){
9540                 return this.getY() + this.getHeight();
9541             }else{
9542                 return (this.getTop(true) + this.getHeight()) || 0;
9543             }
9544         },
9545
9546         /**
9547         * Initializes positioning on this element. If a desired position is not passed, it will make the
9548         * the element positioned relative IF it is not already positioned.
9549         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
9550         * @param {Number} zIndex (optional) The zIndex to apply
9551         * @param {Number} x (optional) Set the page X position
9552         * @param {Number} y (optional) Set the page Y position
9553         */
9554         position : function(pos, zIndex, x, y){
9555             if(!pos){
9556                if(this.getStyle('position') == 'static'){
9557                    this.setStyle('position', 'relative');
9558                }
9559             }else{
9560                 this.setStyle("position", pos);
9561             }
9562             if(zIndex){
9563                 this.setStyle("z-index", zIndex);
9564             }
9565             if(x !== undefined && y !== undefined){
9566                 this.setXY([x, y]);
9567             }else if(x !== undefined){
9568                 this.setX(x);
9569             }else if(y !== undefined){
9570                 this.setY(y);
9571             }
9572         },
9573
9574         /**
9575         * Clear positioning back to the default when the document was loaded
9576         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
9577         * @return {Roo.Element} this
9578          */
9579         clearPositioning : function(value){
9580             value = value ||'';
9581             this.setStyle({
9582                 "left": value,
9583                 "right": value,
9584                 "top": value,
9585                 "bottom": value,
9586                 "z-index": "",
9587                 "position" : "static"
9588             });
9589             return this;
9590         },
9591
9592         /**
9593         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
9594         * snapshot before performing an update and then restoring the element.
9595         * @return {Object}
9596         */
9597         getPositioning : function(){
9598             var l = this.getStyle("left");
9599             var t = this.getStyle("top");
9600             return {
9601                 "position" : this.getStyle("position"),
9602                 "left" : l,
9603                 "right" : l ? "" : this.getStyle("right"),
9604                 "top" : t,
9605                 "bottom" : t ? "" : this.getStyle("bottom"),
9606                 "z-index" : this.getStyle("z-index")
9607             };
9608         },
9609
9610         /**
9611          * Gets the width of the border(s) for the specified side(s)
9612          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
9613          * passing lr would get the border (l)eft width + the border (r)ight width.
9614          * @return {Number} The width of the sides passed added together
9615          */
9616         getBorderWidth : function(side){
9617             return this.addStyles(side, El.borders);
9618         },
9619
9620         /**
9621          * Gets the width of the padding(s) for the specified side(s)
9622          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
9623          * passing lr would get the padding (l)eft + the padding (r)ight.
9624          * @return {Number} The padding of the sides passed added together
9625          */
9626         getPadding : function(side){
9627             return this.addStyles(side, El.paddings);
9628         },
9629
9630         /**
9631         * Set positioning with an object returned by getPositioning().
9632         * @param {Object} posCfg
9633         * @return {Roo.Element} this
9634          */
9635         setPositioning : function(pc){
9636             this.applyStyles(pc);
9637             if(pc.right == "auto"){
9638                 this.dom.style.right = "";
9639             }
9640             if(pc.bottom == "auto"){
9641                 this.dom.style.bottom = "";
9642             }
9643             return this;
9644         },
9645
9646         // private
9647         fixDisplay : function(){
9648             if(this.getStyle("display") == "none"){
9649                 this.setStyle("visibility", "hidden");
9650                 this.setStyle("display", this.originalDisplay); // first try reverting to default
9651                 if(this.getStyle("display") == "none"){ // if that fails, default to block
9652                     this.setStyle("display", "block");
9653                 }
9654             }
9655         },
9656
9657         /**
9658          * Quick set left and top adding default units
9659          * @param {String} left The left CSS property value
9660          * @param {String} top The top CSS property value
9661          * @return {Roo.Element} this
9662          */
9663          setLeftTop : function(left, top){
9664             this.dom.style.left = this.addUnits(left);
9665             this.dom.style.top = this.addUnits(top);
9666             return this;
9667         },
9668
9669         /**
9670          * Move this element relative to its current position.
9671          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9672          * @param {Number} distance How far to move the element in pixels
9673          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9674          * @return {Roo.Element} this
9675          */
9676          move : function(direction, distance, animate){
9677             var xy = this.getXY();
9678             direction = direction.toLowerCase();
9679             switch(direction){
9680                 case "l":
9681                 case "left":
9682                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
9683                     break;
9684                case "r":
9685                case "right":
9686                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
9687                     break;
9688                case "t":
9689                case "top":
9690                case "up":
9691                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
9692                     break;
9693                case "b":
9694                case "bottom":
9695                case "down":
9696                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
9697                     break;
9698             }
9699             return this;
9700         },
9701
9702         /**
9703          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
9704          * @return {Roo.Element} this
9705          */
9706         clip : function(){
9707             if(!this.isClipped){
9708                this.isClipped = true;
9709                this.originalClip = {
9710                    "o": this.getStyle("overflow"),
9711                    "x": this.getStyle("overflow-x"),
9712                    "y": this.getStyle("overflow-y")
9713                };
9714                this.setStyle("overflow", "hidden");
9715                this.setStyle("overflow-x", "hidden");
9716                this.setStyle("overflow-y", "hidden");
9717             }
9718             return this;
9719         },
9720
9721         /**
9722          *  Return clipping (overflow) to original clipping before clip() was called
9723          * @return {Roo.Element} this
9724          */
9725         unclip : function(){
9726             if(this.isClipped){
9727                 this.isClipped = false;
9728                 var o = this.originalClip;
9729                 if(o.o){this.setStyle("overflow", o.o);}
9730                 if(o.x){this.setStyle("overflow-x", o.x);}
9731                 if(o.y){this.setStyle("overflow-y", o.y);}
9732             }
9733             return this;
9734         },
9735
9736
9737         /**
9738          * Gets the x,y coordinates specified by the anchor position on the element.
9739          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
9740          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
9741          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
9742          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
9743          * @return {Array} [x, y] An array containing the element's x and y coordinates
9744          */
9745         getAnchorXY : function(anchor, local, s){
9746             //Passing a different size is useful for pre-calculating anchors,
9747             //especially for anchored animations that change the el size.
9748
9749             var w, h, vp = false;
9750             if(!s){
9751                 var d = this.dom;
9752                 if(d == document.body || d == document){
9753                     vp = true;
9754                     w = D.getViewWidth(); h = D.getViewHeight();
9755                 }else{
9756                     w = this.getWidth(); h = this.getHeight();
9757                 }
9758             }else{
9759                 w = s.width;  h = s.height;
9760             }
9761             var x = 0, y = 0, r = Math.round;
9762             switch((anchor || "tl").toLowerCase()){
9763                 case "c":
9764                     x = r(w*.5);
9765                     y = r(h*.5);
9766                 break;
9767                 case "t":
9768                     x = r(w*.5);
9769                     y = 0;
9770                 break;
9771                 case "l":
9772                     x = 0;
9773                     y = r(h*.5);
9774                 break;
9775                 case "r":
9776                     x = w;
9777                     y = r(h*.5);
9778                 break;
9779                 case "b":
9780                     x = r(w*.5);
9781                     y = h;
9782                 break;
9783                 case "tl":
9784                     x = 0;
9785                     y = 0;
9786                 break;
9787                 case "bl":
9788                     x = 0;
9789                     y = h;
9790                 break;
9791                 case "br":
9792                     x = w;
9793                     y = h;
9794                 break;
9795                 case "tr":
9796                     x = w;
9797                     y = 0;
9798                 break;
9799             }
9800             if(local === true){
9801                 return [x, y];
9802             }
9803             if(vp){
9804                 var sc = this.getScroll();
9805                 return [x + sc.left, y + sc.top];
9806             }
9807             //Add the element's offset xy
9808             var o = this.getXY();
9809             return [x+o[0], y+o[1]];
9810         },
9811
9812         /**
9813          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
9814          * supported position values.
9815          * @param {String/HTMLElement/Roo.Element} element The element to align to.
9816          * @param {String} position The position to align to.
9817          * @param {Array} offsets (optional) Offset the positioning by [x, y]
9818          * @return {Array} [x, y]
9819          */
9820         getAlignToXY : function(el, p, o)
9821         {
9822             el = Roo.get(el);
9823             var d = this.dom;
9824             if(!el.dom){
9825                 throw "Element.alignTo with an element that doesn't exist";
9826             }
9827             var c = false; //constrain to viewport
9828             var p1 = "", p2 = "";
9829             o = o || [0,0];
9830
9831             if(!p){
9832                 p = "tl-bl";
9833             }else if(p == "?"){
9834                 p = "tl-bl?";
9835             }else if(p.indexOf("-") == -1){
9836                 p = "tl-" + p;
9837             }
9838             p = p.toLowerCase();
9839             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
9840             if(!m){
9841                throw "Element.alignTo with an invalid alignment " + p;
9842             }
9843             p1 = m[1]; p2 = m[2]; c = !!m[3];
9844
9845             //Subtract the aligned el's internal xy from the target's offset xy
9846             //plus custom offset to get the aligned el's new offset xy
9847             var a1 = this.getAnchorXY(p1, true);
9848             var a2 = el.getAnchorXY(p2, false);
9849             var x = a2[0] - a1[0] + o[0];
9850             var y = a2[1] - a1[1] + o[1];
9851             if(c){
9852                 //constrain the aligned el to viewport if necessary
9853                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
9854                 // 5px of margin for ie
9855                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
9856
9857                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
9858                 //perpendicular to the vp border, allow the aligned el to slide on that border,
9859                 //otherwise swap the aligned el to the opposite border of the target.
9860                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
9861                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
9862                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t")  );
9863                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
9864
9865                var doc = document;
9866                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
9867                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
9868
9869                if((x+w) > dw + scrollX){
9870                     x = swapX ? r.left-w : dw+scrollX-w;
9871                 }
9872                if(x < scrollX){
9873                    x = swapX ? r.right : scrollX;
9874                }
9875                if((y+h) > dh + scrollY){
9876                     y = swapY ? r.top-h : dh+scrollY-h;
9877                 }
9878                if (y < scrollY){
9879                    y = swapY ? r.bottom : scrollY;
9880                }
9881             }
9882             return [x,y];
9883         },
9884
9885         // private
9886         getConstrainToXY : function(){
9887             var os = {top:0, left:0, bottom:0, right: 0};
9888
9889             return function(el, local, offsets, proposedXY){
9890                 el = Roo.get(el);
9891                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
9892
9893                 var vw, vh, vx = 0, vy = 0;
9894                 if(el.dom == document.body || el.dom == document){
9895                     vw = Roo.lib.Dom.getViewWidth();
9896                     vh = Roo.lib.Dom.getViewHeight();
9897                 }else{
9898                     vw = el.dom.clientWidth;
9899                     vh = el.dom.clientHeight;
9900                     if(!local){
9901                         var vxy = el.getXY();
9902                         vx = vxy[0];
9903                         vy = vxy[1];
9904                     }
9905                 }
9906
9907                 var s = el.getScroll();
9908
9909                 vx += offsets.left + s.left;
9910                 vy += offsets.top + s.top;
9911
9912                 vw -= offsets.right;
9913                 vh -= offsets.bottom;
9914
9915                 var vr = vx+vw;
9916                 var vb = vy+vh;
9917
9918                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
9919                 var x = xy[0], y = xy[1];
9920                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
9921
9922                 // only move it if it needs it
9923                 var moved = false;
9924
9925                 // first validate right/bottom
9926                 if((x + w) > vr){
9927                     x = vr - w;
9928                     moved = true;
9929                 }
9930                 if((y + h) > vb){
9931                     y = vb - h;
9932                     moved = true;
9933                 }
9934                 // then make sure top/left isn't negative
9935                 if(x < vx){
9936                     x = vx;
9937                     moved = true;
9938                 }
9939                 if(y < vy){
9940                     y = vy;
9941                     moved = true;
9942                 }
9943                 return moved ? [x, y] : false;
9944             };
9945         }(),
9946
9947         // private
9948         adjustForConstraints : function(xy, parent, offsets){
9949             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
9950         },
9951
9952         /**
9953          * Aligns this element with another element relative to the specified anchor points. If the other element is the
9954          * document it aligns it to the viewport.
9955          * The position parameter is optional, and can be specified in any one of the following formats:
9956          * <ul>
9957          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
9958          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
9959          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
9960          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
9961          *   <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
9962          *       element's anchor point, and the second value is used as the target's anchor point.</li>
9963          * </ul>
9964          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
9965          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
9966          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
9967          * that specified in order to enforce the viewport constraints.
9968          * Following are all of the supported anchor positions:
9969     <pre>
9970     Value  Description
9971     -----  -----------------------------
9972     tl     The top left corner (default)
9973     t      The center of the top edge
9974     tr     The top right corner
9975     l      The center of the left edge
9976     c      In the center of the element
9977     r      The center of the right edge
9978     bl     The bottom left corner
9979     b      The center of the bottom edge
9980     br     The bottom right corner
9981     </pre>
9982     Example Usage:
9983     <pre><code>
9984     // align el to other-el using the default positioning ("tl-bl", non-constrained)
9985     el.alignTo("other-el");
9986
9987     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
9988     el.alignTo("other-el", "tr?");
9989
9990     // align the bottom right corner of el with the center left edge of other-el
9991     el.alignTo("other-el", "br-l?");
9992
9993     // align the center of el with the bottom left corner of other-el and
9994     // adjust the x position by -6 pixels (and the y position by 0)
9995     el.alignTo("other-el", "c-bl", [-6, 0]);
9996     </code></pre>
9997          * @param {String/HTMLElement/Roo.Element} element The element to align to.
9998          * @param {String} position The position to align to.
9999          * @param {Array} offsets (optional) Offset the positioning by [x, y]
10000          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10001          * @return {Roo.Element} this
10002          */
10003         alignTo : function(element, position, offsets, animate){
10004             var xy = this.getAlignToXY(element, position, offsets);
10005             this.setXY(xy, this.preanim(arguments, 3));
10006             return this;
10007         },
10008
10009         /**
10010          * Anchors an element to another element and realigns it when the window is resized.
10011          * @param {String/HTMLElement/Roo.Element} element The element to align to.
10012          * @param {String} position The position to align to.
10013          * @param {Array} offsets (optional) Offset the positioning by [x, y]
10014          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
10015          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
10016          * is a number, it is used as the buffer delay (defaults to 50ms).
10017          * @param {Function} callback The function to call after the animation finishes
10018          * @return {Roo.Element} this
10019          */
10020         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
10021             var action = function(){
10022                 this.alignTo(el, alignment, offsets, animate);
10023                 Roo.callback(callback, this);
10024             };
10025             Roo.EventManager.onWindowResize(action, this);
10026             var tm = typeof monitorScroll;
10027             if(tm != 'undefined'){
10028                 Roo.EventManager.on(window, 'scroll', action, this,
10029                     {buffer: tm == 'number' ? monitorScroll : 50});
10030             }
10031             action.call(this); // align immediately
10032             return this;
10033         },
10034         /**
10035          * Clears any opacity settings from this element. Required in some cases for IE.
10036          * @return {Roo.Element} this
10037          */
10038         clearOpacity : function(){
10039             if (window.ActiveXObject) {
10040                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
10041                     this.dom.style.filter = "";
10042                 }
10043             } else {
10044                 this.dom.style.opacity = "";
10045                 this.dom.style["-moz-opacity"] = "";
10046                 this.dom.style["-khtml-opacity"] = "";
10047             }
10048             return this;
10049         },
10050
10051         /**
10052          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
10053          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10054          * @return {Roo.Element} this
10055          */
10056         hide : function(animate){
10057             this.setVisible(false, this.preanim(arguments, 0));
10058             return this;
10059         },
10060
10061         /**
10062         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
10063         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10064          * @return {Roo.Element} this
10065          */
10066         show : function(animate){
10067             this.setVisible(true, this.preanim(arguments, 0));
10068             return this;
10069         },
10070
10071         /**
10072          * @private Test if size has a unit, otherwise appends the default
10073          */
10074         addUnits : function(size){
10075             return Roo.Element.addUnits(size, this.defaultUnit);
10076         },
10077
10078         /**
10079          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
10080          * @return {Roo.Element} this
10081          */
10082         beginMeasure : function(){
10083             var el = this.dom;
10084             if(el.offsetWidth || el.offsetHeight){
10085                 return this; // offsets work already
10086             }
10087             var changed = [];
10088             var p = this.dom, b = document.body; // start with this element
10089             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
10090                 var pe = Roo.get(p);
10091                 if(pe.getStyle('display') == 'none'){
10092                     changed.push({el: p, visibility: pe.getStyle("visibility")});
10093                     p.style.visibility = "hidden";
10094                     p.style.display = "block";
10095                 }
10096                 p = p.parentNode;
10097             }
10098             this._measureChanged = changed;
10099             return this;
10100
10101         },
10102
10103         /**
10104          * Restores displays to before beginMeasure was called
10105          * @return {Roo.Element} this
10106          */
10107         endMeasure : function(){
10108             var changed = this._measureChanged;
10109             if(changed){
10110                 for(var i = 0, len = changed.length; i < len; i++) {
10111                     var r = changed[i];
10112                     r.el.style.visibility = r.visibility;
10113                     r.el.style.display = "none";
10114                 }
10115                 this._measureChanged = null;
10116             }
10117             return this;
10118         },
10119
10120         /**
10121         * Update the innerHTML of this element, optionally searching for and processing scripts
10122         * @param {String} html The new HTML
10123         * @param {Boolean} loadScripts (optional) true to look for and process scripts
10124         * @param {Function} callback For async script loading you can be noticed when the update completes
10125         * @return {Roo.Element} this
10126          */
10127         update : function(html, loadScripts, callback){
10128             if(typeof html == "undefined"){
10129                 html = "";
10130             }
10131             if(loadScripts !== true){
10132                 this.dom.innerHTML = html;
10133                 if(typeof callback == "function"){
10134                     callback();
10135                 }
10136                 return this;
10137             }
10138             var id = Roo.id();
10139             var dom = this.dom;
10140
10141             html += '<span id="' + id + '"></span>';
10142
10143             E.onAvailable(id, function(){
10144                 var hd = document.getElementsByTagName("head")[0];
10145                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
10146                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
10147                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
10148
10149                 var match;
10150                 while(match = re.exec(html)){
10151                     var attrs = match[1];
10152                     var srcMatch = attrs ? attrs.match(srcRe) : false;
10153                     if(srcMatch && srcMatch[2]){
10154                        var s = document.createElement("script");
10155                        s.src = srcMatch[2];
10156                        var typeMatch = attrs.match(typeRe);
10157                        if(typeMatch && typeMatch[2]){
10158                            s.type = typeMatch[2];
10159                        }
10160                        hd.appendChild(s);
10161                     }else if(match[2] && match[2].length > 0){
10162                         if(window.execScript) {
10163                            window.execScript(match[2]);
10164                         } else {
10165                             /**
10166                              * eval:var:id
10167                              * eval:var:dom
10168                              * eval:var:html
10169                              * 
10170                              */
10171                            window.eval(match[2]);
10172                         }
10173                     }
10174                 }
10175                 var el = document.getElementById(id);
10176                 if(el){el.parentNode.removeChild(el);}
10177                 if(typeof callback == "function"){
10178                     callback();
10179                 }
10180             });
10181             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
10182             return this;
10183         },
10184
10185         /**
10186          * Direct access to the UpdateManager update() method (takes the same parameters).
10187          * @param {String/Function} url The url for this request or a function to call to get the url
10188          * @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}
10189          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
10190          * @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.
10191          * @return {Roo.Element} this
10192          */
10193         load : function(){
10194             var um = this.getUpdateManager();
10195             um.update.apply(um, arguments);
10196             return this;
10197         },
10198
10199         /**
10200         * Gets this element's UpdateManager
10201         * @return {Roo.UpdateManager} The UpdateManager
10202         */
10203         getUpdateManager : function(){
10204             if(!this.updateManager){
10205                 this.updateManager = new Roo.UpdateManager(this);
10206             }
10207             return this.updateManager;
10208         },
10209
10210         /**
10211          * Disables text selection for this element (normalized across browsers)
10212          * @return {Roo.Element} this
10213          */
10214         unselectable : function(){
10215             this.dom.unselectable = "on";
10216             this.swallowEvent("selectstart", true);
10217             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
10218             this.addClass("x-unselectable");
10219             return this;
10220         },
10221
10222         /**
10223         * Calculates the x, y to center this element on the screen
10224         * @return {Array} The x, y values [x, y]
10225         */
10226         getCenterXY : function(){
10227             return this.getAlignToXY(document, 'c-c');
10228         },
10229
10230         /**
10231         * Centers the Element in either the viewport, or another Element.
10232         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
10233         */
10234         center : function(centerIn){
10235             this.alignTo(centerIn || document, 'c-c');
10236             return this;
10237         },
10238
10239         /**
10240          * Tests various css rules/browsers to determine if this element uses a border box
10241          * @return {Boolean}
10242          */
10243         isBorderBox : function(){
10244             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
10245         },
10246
10247         /**
10248          * Return a box {x, y, width, height} that can be used to set another elements
10249          * size/location to match this element.
10250          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
10251          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
10252          * @return {Object} box An object in the format {x, y, width, height}
10253          */
10254         getBox : function(contentBox, local){
10255             var xy;
10256             if(!local){
10257                 xy = this.getXY();
10258             }else{
10259                 var left = parseInt(this.getStyle("left"), 10) || 0;
10260                 var top = parseInt(this.getStyle("top"), 10) || 0;
10261                 xy = [left, top];
10262             }
10263             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
10264             if(!contentBox){
10265                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
10266             }else{
10267                 var l = this.getBorderWidth("l")+this.getPadding("l");
10268                 var r = this.getBorderWidth("r")+this.getPadding("r");
10269                 var t = this.getBorderWidth("t")+this.getPadding("t");
10270                 var b = this.getBorderWidth("b")+this.getPadding("b");
10271                 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)};
10272             }
10273             bx.right = bx.x + bx.width;
10274             bx.bottom = bx.y + bx.height;
10275             return bx;
10276         },
10277
10278         /**
10279          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
10280          for more information about the sides.
10281          * @param {String} sides
10282          * @return {Number}
10283          */
10284         getFrameWidth : function(sides, onlyContentBox){
10285             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
10286         },
10287
10288         /**
10289          * 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.
10290          * @param {Object} box The box to fill {x, y, width, height}
10291          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
10292          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10293          * @return {Roo.Element} this
10294          */
10295         setBox : function(box, adjust, animate){
10296             var w = box.width, h = box.height;
10297             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
10298                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
10299                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
10300             }
10301             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
10302             return this;
10303         },
10304
10305         /**
10306          * Forces the browser to repaint this element
10307          * @return {Roo.Element} this
10308          */
10309          repaint : function(){
10310             var dom = this.dom;
10311             this.addClass("x-repaint");
10312             setTimeout(function(){
10313                 Roo.get(dom).removeClass("x-repaint");
10314             }, 1);
10315             return this;
10316         },
10317
10318         /**
10319          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
10320          * then it returns the calculated width of the sides (see getPadding)
10321          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
10322          * @return {Object/Number}
10323          */
10324         getMargins : function(side){
10325             if(!side){
10326                 return {
10327                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
10328                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
10329                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
10330                     right: parseInt(this.getStyle("margin-right"), 10) || 0
10331                 };
10332             }else{
10333                 return this.addStyles(side, El.margins);
10334              }
10335         },
10336
10337         // private
10338         addStyles : function(sides, styles){
10339             var val = 0, v, w;
10340             for(var i = 0, len = sides.length; i < len; i++){
10341                 v = this.getStyle(styles[sides.charAt(i)]);
10342                 if(v){
10343                      w = parseInt(v, 10);
10344                      if(w){ val += w; }
10345                 }
10346             }
10347             return val;
10348         },
10349
10350         /**
10351          * Creates a proxy element of this element
10352          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
10353          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
10354          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
10355          * @return {Roo.Element} The new proxy element
10356          */
10357         createProxy : function(config, renderTo, matchBox){
10358             if(renderTo){
10359                 renderTo = Roo.getDom(renderTo);
10360             }else{
10361                 renderTo = document.body;
10362             }
10363             config = typeof config == "object" ?
10364                 config : {tag : "div", cls: config};
10365             var proxy = Roo.DomHelper.append(renderTo, config, true);
10366             if(matchBox){
10367                proxy.setBox(this.getBox());
10368             }
10369             return proxy;
10370         },
10371
10372         /**
10373          * Puts a mask over this element to disable user interaction. Requires core.css.
10374          * This method can only be applied to elements which accept child nodes.
10375          * @param {String} msg (optional) A message to display in the mask
10376          * @param {String} msgCls (optional) A css class to apply to the msg element - use no-spinner to hide the spinner on bootstrap
10377          * @return {Element} The mask  element
10378          */
10379         mask : function(msg, msgCls)
10380         {
10381             if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
10382                 this.setStyle("position", "relative");
10383             }
10384             if(!this._mask){
10385                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
10386             }
10387             
10388             this.addClass("x-masked");
10389             this._mask.setDisplayed(true);
10390             
10391             // we wander
10392             var z = 0;
10393             var dom = this.dom;
10394             while (dom && dom.style) {
10395                 if (!isNaN(parseInt(dom.style.zIndex))) {
10396                     z = Math.max(z, parseInt(dom.style.zIndex));
10397                 }
10398                 dom = dom.parentNode;
10399             }
10400             // if we are masking the body - then it hides everything..
10401             if (this.dom == document.body) {
10402                 z = 1000000;
10403                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
10404                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
10405             }
10406            
10407             if(typeof msg == 'string'){
10408                 if(!this._maskMsg){
10409                     this._maskMsg = Roo.DomHelper.append(this.dom, {
10410                         cls: "roo-el-mask-msg", 
10411                         cn: [
10412                             {
10413                                 tag: 'i',
10414                                 cls: 'fa fa-spinner fa-spin'
10415                             },
10416                             {
10417                                 tag: 'div'
10418                             }   
10419                         ]
10420                     }, true);
10421                 }
10422                 var mm = this._maskMsg;
10423                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
10424                 if (mm.dom.lastChild) { // weird IE issue?
10425                     mm.dom.lastChild.innerHTML = msg;
10426                 }
10427                 mm.setDisplayed(true);
10428                 mm.center(this);
10429                 mm.setStyle('z-index', z + 102);
10430             }
10431             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
10432                 this._mask.setHeight(this.getHeight());
10433             }
10434             this._mask.setStyle('z-index', z + 100);
10435             
10436             return this._mask;
10437         },
10438
10439         /**
10440          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
10441          * it is cached for reuse.
10442          */
10443         unmask : function(removeEl){
10444             if(this._mask){
10445                 if(removeEl === true){
10446                     this._mask.remove();
10447                     delete this._mask;
10448                     if(this._maskMsg){
10449                         this._maskMsg.remove();
10450                         delete this._maskMsg;
10451                     }
10452                 }else{
10453                     this._mask.setDisplayed(false);
10454                     if(this._maskMsg){
10455                         this._maskMsg.setDisplayed(false);
10456                     }
10457                 }
10458             }
10459             this.removeClass("x-masked");
10460         },
10461
10462         /**
10463          * Returns true if this element is masked
10464          * @return {Boolean}
10465          */
10466         isMasked : function(){
10467             return this._mask && this._mask.isVisible();
10468         },
10469
10470         /**
10471          * Creates an iframe shim for this element to keep selects and other windowed objects from
10472          * showing through.
10473          * @return {Roo.Element} The new shim element
10474          */
10475         createShim : function(){
10476             var el = document.createElement('iframe');
10477             el.frameBorder = 'no';
10478             el.className = 'roo-shim';
10479             if(Roo.isIE && Roo.isSecure){
10480                 el.src = Roo.SSL_SECURE_URL;
10481             }
10482             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
10483             shim.autoBoxAdjust = false;
10484             return shim;
10485         },
10486
10487         /**
10488          * Removes this element from the DOM and deletes it from the cache
10489          */
10490         remove : function(){
10491             if(this.dom.parentNode){
10492                 this.dom.parentNode.removeChild(this.dom);
10493             }
10494             delete El.cache[this.dom.id];
10495         },
10496
10497         /**
10498          * Sets up event handlers to add and remove a css class when the mouse is over this element
10499          * @param {String} className
10500          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
10501          * mouseout events for children elements
10502          * @return {Roo.Element} this
10503          */
10504         addClassOnOver : function(className, preventFlicker){
10505             this.on("mouseover", function(){
10506                 Roo.fly(this, '_internal').addClass(className);
10507             }, this.dom);
10508             var removeFn = function(e){
10509                 if(preventFlicker !== true || !e.within(this, true)){
10510                     Roo.fly(this, '_internal').removeClass(className);
10511                 }
10512             };
10513             this.on("mouseout", removeFn, this.dom);
10514             return this;
10515         },
10516
10517         /**
10518          * Sets up event handlers to add and remove a css class when this element has the focus
10519          * @param {String} className
10520          * @return {Roo.Element} this
10521          */
10522         addClassOnFocus : function(className){
10523             this.on("focus", function(){
10524                 Roo.fly(this, '_internal').addClass(className);
10525             }, this.dom);
10526             this.on("blur", function(){
10527                 Roo.fly(this, '_internal').removeClass(className);
10528             }, this.dom);
10529             return this;
10530         },
10531         /**
10532          * 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)
10533          * @param {String} className
10534          * @return {Roo.Element} this
10535          */
10536         addClassOnClick : function(className){
10537             var dom = this.dom;
10538             this.on("mousedown", function(){
10539                 Roo.fly(dom, '_internal').addClass(className);
10540                 var d = Roo.get(document);
10541                 var fn = function(){
10542                     Roo.fly(dom, '_internal').removeClass(className);
10543                     d.removeListener("mouseup", fn);
10544                 };
10545                 d.on("mouseup", fn);
10546             });
10547             return this;
10548         },
10549
10550         /**
10551          * Stops the specified event from bubbling and optionally prevents the default action
10552          * @param {String} eventName
10553          * @param {Boolean} preventDefault (optional) true to prevent the default action too
10554          * @return {Roo.Element} this
10555          */
10556         swallowEvent : function(eventName, preventDefault){
10557             var fn = function(e){
10558                 e.stopPropagation();
10559                 if(preventDefault){
10560                     e.preventDefault();
10561                 }
10562             };
10563             if(eventName instanceof Array){
10564                 for(var i = 0, len = eventName.length; i < len; i++){
10565                      this.on(eventName[i], fn);
10566                 }
10567                 return this;
10568             }
10569             this.on(eventName, fn);
10570             return this;
10571         },
10572
10573         /**
10574          * @private
10575          */
10576         fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
10577
10578         /**
10579          * Sizes this element to its parent element's dimensions performing
10580          * neccessary box adjustments.
10581          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
10582          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
10583          * @return {Roo.Element} this
10584          */
10585         fitToParent : function(monitorResize, targetParent) {
10586           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
10587           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
10588           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
10589             return this;
10590           }
10591           var p = Roo.get(targetParent || this.dom.parentNode);
10592           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
10593           if (monitorResize === true) {
10594             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
10595             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
10596           }
10597           return this;
10598         },
10599
10600         /**
10601          * Gets the next sibling, skipping text nodes
10602          * @return {HTMLElement} The next sibling or null
10603          */
10604         getNextSibling : function(){
10605             var n = this.dom.nextSibling;
10606             while(n && n.nodeType != 1){
10607                 n = n.nextSibling;
10608             }
10609             return n;
10610         },
10611
10612         /**
10613          * Gets the previous sibling, skipping text nodes
10614          * @return {HTMLElement} The previous sibling or null
10615          */
10616         getPrevSibling : function(){
10617             var n = this.dom.previousSibling;
10618             while(n && n.nodeType != 1){
10619                 n = n.previousSibling;
10620             }
10621             return n;
10622         },
10623
10624
10625         /**
10626          * Appends the passed element(s) to this element
10627          * @param {String/HTMLElement/Array/Element/CompositeElement} el
10628          * @return {Roo.Element} this
10629          */
10630         appendChild: function(el){
10631             el = Roo.get(el);
10632             el.appendTo(this);
10633             return this;
10634         },
10635
10636         /**
10637          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
10638          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
10639          * automatically generated with the specified attributes.
10640          * @param {HTMLElement} insertBefore (optional) a child element of this element
10641          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
10642          * @return {Roo.Element} The new child element
10643          */
10644         createChild: function(config, insertBefore, returnDom){
10645             config = config || {tag:'div'};
10646             if(insertBefore){
10647                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
10648             }
10649             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
10650         },
10651
10652         /**
10653          * Appends this element to the passed element
10654          * @param {String/HTMLElement/Element} el The new parent element
10655          * @return {Roo.Element} this
10656          */
10657         appendTo: function(el){
10658             el = Roo.getDom(el);
10659             el.appendChild(this.dom);
10660             return this;
10661         },
10662
10663         /**
10664          * Inserts this element before the passed element in the DOM
10665          * @param {String/HTMLElement/Element} el The element to insert before
10666          * @return {Roo.Element} this
10667          */
10668         insertBefore: function(el){
10669             el = Roo.getDom(el);
10670             el.parentNode.insertBefore(this.dom, el);
10671             return this;
10672         },
10673
10674         /**
10675          * Inserts this element after the passed element in the DOM
10676          * @param {String/HTMLElement/Element} el The element to insert after
10677          * @return {Roo.Element} this
10678          */
10679         insertAfter: function(el){
10680             el = Roo.getDom(el);
10681             el.parentNode.insertBefore(this.dom, el.nextSibling);
10682             return this;
10683         },
10684
10685         /**
10686          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
10687          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
10688          * @return {Roo.Element} The new child
10689          */
10690         insertFirst: function(el, returnDom){
10691             el = el || {};
10692             if(typeof el == 'object' && !el.nodeType){ // dh config
10693                 return this.createChild(el, this.dom.firstChild, returnDom);
10694             }else{
10695                 el = Roo.getDom(el);
10696                 this.dom.insertBefore(el, this.dom.firstChild);
10697                 return !returnDom ? Roo.get(el) : el;
10698             }
10699         },
10700
10701         /**
10702          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
10703          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
10704          * @param {String} where (optional) 'before' or 'after' defaults to before
10705          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
10706          * @return {Roo.Element} the inserted Element
10707          */
10708         insertSibling: function(el, where, returnDom){
10709             where = where ? where.toLowerCase() : 'before';
10710             el = el || {};
10711             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
10712
10713             if(typeof el == 'object' && !el.nodeType){ // dh config
10714                 if(where == 'after' && !this.dom.nextSibling){
10715                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
10716                 }else{
10717                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
10718                 }
10719
10720             }else{
10721                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
10722                             where == 'before' ? this.dom : this.dom.nextSibling);
10723                 if(!returnDom){
10724                     rt = Roo.get(rt);
10725                 }
10726             }
10727             return rt;
10728         },
10729
10730         /**
10731          * Creates and wraps this element with another element
10732          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
10733          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
10734          * @return {HTMLElement/Element} The newly created wrapper element
10735          */
10736         wrap: function(config, returnDom){
10737             if(!config){
10738                 config = {tag: "div"};
10739             }
10740             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
10741             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
10742             return newEl;
10743         },
10744
10745         /**
10746          * Replaces the passed element with this element
10747          * @param {String/HTMLElement/Element} el The element to replace
10748          * @return {Roo.Element} this
10749          */
10750         replace: function(el){
10751             el = Roo.get(el);
10752             this.insertBefore(el);
10753             el.remove();
10754             return this;
10755         },
10756
10757         /**
10758          * Inserts an html fragment into this element
10759          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
10760          * @param {String} html The HTML fragment
10761          * @param {Boolean} returnEl True to return an Roo.Element
10762          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
10763          */
10764         insertHtml : function(where, html, returnEl){
10765             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
10766             return returnEl ? Roo.get(el) : el;
10767         },
10768
10769         /**
10770          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
10771          * @param {Object} o The object with the attributes
10772          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
10773          * @return {Roo.Element} this
10774          */
10775         set : function(o, useSet){
10776             var el = this.dom;
10777             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
10778             for(var attr in o){
10779                 if(attr == "style" || typeof o[attr] == "function")  { continue; }
10780                 if(attr=="cls"){
10781                     el.className = o["cls"];
10782                 }else{
10783                     if(useSet) {
10784                         el.setAttribute(attr, o[attr]);
10785                     } else {
10786                         el[attr] = o[attr];
10787                     }
10788                 }
10789             }
10790             if(o.style){
10791                 Roo.DomHelper.applyStyles(el, o.style);
10792             }
10793             return this;
10794         },
10795
10796         /**
10797          * Convenience method for constructing a KeyMap
10798          * @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:
10799          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
10800          * @param {Function} fn The function to call
10801          * @param {Object} scope (optional) The scope of the function
10802          * @return {Roo.KeyMap} The KeyMap created
10803          */
10804         addKeyListener : function(key, fn, scope){
10805             var config;
10806             if(typeof key != "object" || key instanceof Array){
10807                 config = {
10808                     key: key,
10809                     fn: fn,
10810                     scope: scope
10811                 };
10812             }else{
10813                 config = {
10814                     key : key.key,
10815                     shift : key.shift,
10816                     ctrl : key.ctrl,
10817                     alt : key.alt,
10818                     fn: fn,
10819                     scope: scope
10820                 };
10821             }
10822             return new Roo.KeyMap(this, config);
10823         },
10824
10825         /**
10826          * Creates a KeyMap for this element
10827          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
10828          * @return {Roo.KeyMap} The KeyMap created
10829          */
10830         addKeyMap : function(config){
10831             return new Roo.KeyMap(this, config);
10832         },
10833
10834         /**
10835          * Returns true if this element is scrollable.
10836          * @return {Boolean}
10837          */
10838          isScrollable : function(){
10839             var dom = this.dom;
10840             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
10841         },
10842
10843         /**
10844          * 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().
10845          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
10846          * @param {Number} value The new scroll value
10847          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10848          * @return {Element} this
10849          */
10850
10851         scrollTo : function(side, value, animate){
10852             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
10853             if(!animate || !A){
10854                 this.dom[prop] = value;
10855             }else{
10856                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
10857                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
10858             }
10859             return this;
10860         },
10861
10862         /**
10863          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
10864          * within this element's scrollable range.
10865          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
10866          * @param {Number} distance How far to scroll the element in pixels
10867          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10868          * @return {Boolean} Returns true if a scroll was triggered or false if the element
10869          * was scrolled as far as it could go.
10870          */
10871          scroll : function(direction, distance, animate){
10872              if(!this.isScrollable()){
10873                  return;
10874              }
10875              var el = this.dom;
10876              var l = el.scrollLeft, t = el.scrollTop;
10877              var w = el.scrollWidth, h = el.scrollHeight;
10878              var cw = el.clientWidth, ch = el.clientHeight;
10879              direction = direction.toLowerCase();
10880              var scrolled = false;
10881              var a = this.preanim(arguments, 2);
10882              switch(direction){
10883                  case "l":
10884                  case "left":
10885                      if(w - l > cw){
10886                          var v = Math.min(l + distance, w-cw);
10887                          this.scrollTo("left", v, a);
10888                          scrolled = true;
10889                      }
10890                      break;
10891                 case "r":
10892                 case "right":
10893                      if(l > 0){
10894                          var v = Math.max(l - distance, 0);
10895                          this.scrollTo("left", v, a);
10896                          scrolled = true;
10897                      }
10898                      break;
10899                 case "t":
10900                 case "top":
10901                 case "up":
10902                      if(t > 0){
10903                          var v = Math.max(t - distance, 0);
10904                          this.scrollTo("top", v, a);
10905                          scrolled = true;
10906                      }
10907                      break;
10908                 case "b":
10909                 case "bottom":
10910                 case "down":
10911                      if(h - t > ch){
10912                          var v = Math.min(t + distance, h-ch);
10913                          this.scrollTo("top", v, a);
10914                          scrolled = true;
10915                      }
10916                      break;
10917              }
10918              return scrolled;
10919         },
10920
10921         /**
10922          * Translates the passed page coordinates into left/top css values for this element
10923          * @param {Number/Array} x The page x or an array containing [x, y]
10924          * @param {Number} y The page y
10925          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
10926          */
10927         translatePoints : function(x, y){
10928             if(typeof x == 'object' || x instanceof Array){
10929                 y = x[1]; x = x[0];
10930             }
10931             var p = this.getStyle('position');
10932             var o = this.getXY();
10933
10934             var l = parseInt(this.getStyle('left'), 10);
10935             var t = parseInt(this.getStyle('top'), 10);
10936
10937             if(isNaN(l)){
10938                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
10939             }
10940             if(isNaN(t)){
10941                 t = (p == "relative") ? 0 : this.dom.offsetTop;
10942             }
10943
10944             return {left: (x - o[0] + l), top: (y - o[1] + t)};
10945         },
10946
10947         /**
10948          * Returns the current scroll position of the element.
10949          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
10950          */
10951         getScroll : function(){
10952             var d = this.dom, doc = document;
10953             if(d == doc || d == doc.body){
10954                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
10955                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
10956                 return {left: l, top: t};
10957             }else{
10958                 return {left: d.scrollLeft, top: d.scrollTop};
10959             }
10960         },
10961
10962         /**
10963          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
10964          * are convert to standard 6 digit hex color.
10965          * @param {String} attr The css attribute
10966          * @param {String} defaultValue The default value to use when a valid color isn't found
10967          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
10968          * YUI color anims.
10969          */
10970         getColor : function(attr, defaultValue, prefix){
10971             var v = this.getStyle(attr);
10972             if(!v || v == "transparent" || v == "inherit") {
10973                 return defaultValue;
10974             }
10975             var color = typeof prefix == "undefined" ? "#" : prefix;
10976             if(v.substr(0, 4) == "rgb("){
10977                 var rvs = v.slice(4, v.length -1).split(",");
10978                 for(var i = 0; i < 3; i++){
10979                     var h = parseInt(rvs[i]).toString(16);
10980                     if(h < 16){
10981                         h = "0" + h;
10982                     }
10983                     color += h;
10984                 }
10985             } else {
10986                 if(v.substr(0, 1) == "#"){
10987                     if(v.length == 4) {
10988                         for(var i = 1; i < 4; i++){
10989                             var c = v.charAt(i);
10990                             color +=  c + c;
10991                         }
10992                     }else if(v.length == 7){
10993                         color += v.substr(1);
10994                     }
10995                 }
10996             }
10997             return(color.length > 5 ? color.toLowerCase() : defaultValue);
10998         },
10999
11000         /**
11001          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
11002          * gradient background, rounded corners and a 4-way shadow.
11003          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
11004          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
11005          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
11006          * @return {Roo.Element} this
11007          */
11008         boxWrap : function(cls){
11009             cls = cls || 'x-box';
11010             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
11011             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
11012             return el;
11013         },
11014
11015         /**
11016          * Returns the value of a namespaced attribute from the element's underlying DOM node.
11017          * @param {String} namespace The namespace in which to look for the attribute
11018          * @param {String} name The attribute name
11019          * @return {String} The attribute value
11020          */
11021         getAttributeNS : Roo.isIE ? function(ns, name){
11022             var d = this.dom;
11023             var type = typeof d[ns+":"+name];
11024             if(type != 'undefined' && type != 'unknown'){
11025                 return d[ns+":"+name];
11026             }
11027             return d[name];
11028         } : function(ns, name){
11029             var d = this.dom;
11030             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
11031         },
11032         
11033         
11034         /**
11035          * Sets or Returns the value the dom attribute value
11036          * @param {String|Object} name The attribute name (or object to set multiple attributes)
11037          * @param {String} value (optional) The value to set the attribute to
11038          * @return {String} The attribute value
11039          */
11040         attr : function(name){
11041             if (arguments.length > 1) {
11042                 this.dom.setAttribute(name, arguments[1]);
11043                 return arguments[1];
11044             }
11045             if (typeof(name) == 'object') {
11046                 for(var i in name) {
11047                     this.attr(i, name[i]);
11048                 }
11049                 return name;
11050             }
11051             
11052             
11053             if (!this.dom.hasAttribute(name)) {
11054                 return undefined;
11055             }
11056             return this.dom.getAttribute(name);
11057         }
11058         
11059         
11060         
11061     };
11062
11063     var ep = El.prototype;
11064
11065     /**
11066      * Appends an event handler (Shorthand for addListener)
11067      * @param {String}   eventName     The type of event to append
11068      * @param {Function} fn        The method the event invokes
11069      * @param {Object} scope       (optional) The scope (this object) of the fn
11070      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
11071      * @method
11072      */
11073     ep.on = ep.addListener;
11074         // backwards compat
11075     ep.mon = ep.addListener;
11076
11077     /**
11078      * Removes an event handler from this element (shorthand for removeListener)
11079      * @param {String} eventName the type of event to remove
11080      * @param {Function} fn the method the event invokes
11081      * @return {Roo.Element} this
11082      * @method
11083      */
11084     ep.un = ep.removeListener;
11085
11086     /**
11087      * true to automatically adjust width and height settings for box-model issues (default to true)
11088      */
11089     ep.autoBoxAdjust = true;
11090
11091     // private
11092     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
11093
11094     // private
11095     El.addUnits = function(v, defaultUnit){
11096         if(v === "" || v == "auto"){
11097             return v;
11098         }
11099         if(v === undefined){
11100             return '';
11101         }
11102         if(typeof v == "number" || !El.unitPattern.test(v)){
11103             return v + (defaultUnit || 'px');
11104         }
11105         return v;
11106     };
11107
11108     // special markup used throughout Roo when box wrapping elements
11109     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>';
11110     /**
11111      * Visibility mode constant - Use visibility to hide element
11112      * @static
11113      * @type Number
11114      */
11115     El.VISIBILITY = 1;
11116     /**
11117      * Visibility mode constant - Use display to hide element
11118      * @static
11119      * @type Number
11120      */
11121     El.DISPLAY = 2;
11122
11123     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
11124     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
11125     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
11126
11127
11128
11129     /**
11130      * @private
11131      */
11132     El.cache = {};
11133
11134     var docEl;
11135
11136     /**
11137      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
11138      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
11139      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
11140      * @return {Element} The Element object
11141      * @static
11142      */
11143     El.get = function(el){
11144         var ex, elm, id;
11145         if(!el){ return null; }
11146         if(typeof el == "string"){ // element id
11147             if(!(elm = document.getElementById(el))){
11148                 return null;
11149             }
11150             if(ex = El.cache[el]){
11151                 ex.dom = elm;
11152             }else{
11153                 ex = El.cache[el] = new El(elm);
11154             }
11155             return ex;
11156         }else if(el.tagName){ // dom element
11157             if(!(id = el.id)){
11158                 id = Roo.id(el);
11159             }
11160             if(ex = El.cache[id]){
11161                 ex.dom = el;
11162             }else{
11163                 ex = El.cache[id] = new El(el);
11164             }
11165             return ex;
11166         }else if(el instanceof El){
11167             if(el != docEl){
11168                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
11169                                                               // catch case where it hasn't been appended
11170                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
11171             }
11172             return el;
11173         }else if(el.isComposite){
11174             return el;
11175         }else if(el instanceof Array){
11176             return El.select(el);
11177         }else if(el == document){
11178             // create a bogus element object representing the document object
11179             if(!docEl){
11180                 var f = function(){};
11181                 f.prototype = El.prototype;
11182                 docEl = new f();
11183                 docEl.dom = document;
11184             }
11185             return docEl;
11186         }
11187         return null;
11188     };
11189
11190     // private
11191     El.uncache = function(el){
11192         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
11193             if(a[i]){
11194                 delete El.cache[a[i].id || a[i]];
11195             }
11196         }
11197     };
11198
11199     // private
11200     // Garbage collection - uncache elements/purge listeners on orphaned elements
11201     // so we don't hold a reference and cause the browser to retain them
11202     El.garbageCollect = function(){
11203         if(!Roo.enableGarbageCollector){
11204             clearInterval(El.collectorThread);
11205             return;
11206         }
11207         for(var eid in El.cache){
11208             var el = El.cache[eid], d = el.dom;
11209             // -------------------------------------------------------
11210             // Determining what is garbage:
11211             // -------------------------------------------------------
11212             // !d
11213             // dom node is null, definitely garbage
11214             // -------------------------------------------------------
11215             // !d.parentNode
11216             // no parentNode == direct orphan, definitely garbage
11217             // -------------------------------------------------------
11218             // !d.offsetParent && !document.getElementById(eid)
11219             // display none elements have no offsetParent so we will
11220             // also try to look it up by it's id. However, check
11221             // offsetParent first so we don't do unneeded lookups.
11222             // This enables collection of elements that are not orphans
11223             // directly, but somewhere up the line they have an orphan
11224             // parent.
11225             // -------------------------------------------------------
11226             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
11227                 delete El.cache[eid];
11228                 if(d && Roo.enableListenerCollection){
11229                     E.purgeElement(d);
11230                 }
11231             }
11232         }
11233     }
11234     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
11235
11236
11237     // dom is optional
11238     El.Flyweight = function(dom){
11239         this.dom = dom;
11240     };
11241     El.Flyweight.prototype = El.prototype;
11242
11243     El._flyweights = {};
11244     /**
11245      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
11246      * the dom node can be overwritten by other code.
11247      * @param {String/HTMLElement} el The dom node or id
11248      * @param {String} named (optional) Allows for creation of named reusable flyweights to
11249      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
11250      * @static
11251      * @return {Element} The shared Element object
11252      */
11253     El.fly = function(el, named){
11254         named = named || '_global';
11255         el = Roo.getDom(el);
11256         if(!el){
11257             return null;
11258         }
11259         if(!El._flyweights[named]){
11260             El._flyweights[named] = new El.Flyweight();
11261         }
11262         El._flyweights[named].dom = el;
11263         return El._flyweights[named];
11264     };
11265
11266     /**
11267      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
11268      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
11269      * Shorthand of {@link Roo.Element#get}
11270      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
11271      * @return {Element} The Element object
11272      * @member Roo
11273      * @method get
11274      */
11275     Roo.get = El.get;
11276     /**
11277      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
11278      * the dom node can be overwritten by other code.
11279      * Shorthand of {@link Roo.Element#fly}
11280      * @param {String/HTMLElement} el The dom node or id
11281      * @param {String} named (optional) Allows for creation of named reusable flyweights to
11282      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
11283      * @static
11284      * @return {Element} The shared Element object
11285      * @member Roo
11286      * @method fly
11287      */
11288     Roo.fly = El.fly;
11289
11290     // speedy lookup for elements never to box adjust
11291     var noBoxAdjust = Roo.isStrict ? {
11292         select:1
11293     } : {
11294         input:1, select:1, textarea:1
11295     };
11296     if(Roo.isIE || Roo.isGecko){
11297         noBoxAdjust['button'] = 1;
11298     }
11299
11300
11301     Roo.EventManager.on(window, 'unload', function(){
11302         delete El.cache;
11303         delete El._flyweights;
11304     });
11305 })();
11306
11307
11308
11309
11310 if(Roo.DomQuery){
11311     Roo.Element.selectorFunction = Roo.DomQuery.select;
11312 }
11313
11314 Roo.Element.select = function(selector, unique, root){
11315     var els;
11316     if(typeof selector == "string"){
11317         els = Roo.Element.selectorFunction(selector, root);
11318     }else if(selector.length !== undefined){
11319         els = selector;
11320     }else{
11321         throw "Invalid selector";
11322     }
11323     if(unique === true){
11324         return new Roo.CompositeElement(els);
11325     }else{
11326         return new Roo.CompositeElementLite(els);
11327     }
11328 };
11329 /**
11330  * Selects elements based on the passed CSS selector to enable working on them as 1.
11331  * @param {String/Array} selector The CSS selector or an array of elements
11332  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
11333  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
11334  * @return {CompositeElementLite/CompositeElement}
11335  * @member Roo
11336  * @method select
11337  */
11338 Roo.select = Roo.Element.select;
11339
11340
11341
11342
11343
11344
11345
11346
11347
11348
11349
11350
11351
11352
11353 /*
11354  * Based on:
11355  * Ext JS Library 1.1.1
11356  * Copyright(c) 2006-2007, Ext JS, LLC.
11357  *
11358  * Originally Released Under LGPL - original licence link has changed is not relivant.
11359  *
11360  * Fork - LGPL
11361  * <script type="text/javascript">
11362  */
11363
11364
11365
11366 //Notifies Element that fx methods are available
11367 Roo.enableFx = true;
11368
11369 /**
11370  * @class Roo.Fx
11371  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
11372  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
11373  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
11374  * Element effects to work.</p><br/>
11375  *
11376  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
11377  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
11378  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
11379  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
11380  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
11381  * expected results and should be done with care.</p><br/>
11382  *
11383  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
11384  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
11385 <pre>
11386 Value  Description
11387 -----  -----------------------------
11388 tl     The top left corner
11389 t      The center of the top edge
11390 tr     The top right corner
11391 l      The center of the left edge
11392 r      The center of the right edge
11393 bl     The bottom left corner
11394 b      The center of the bottom edge
11395 br     The bottom right corner
11396 </pre>
11397  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
11398  * below are common options that can be passed to any Fx method.</b>
11399  * @cfg {Function} callback A function called when the effect is finished
11400  * @cfg {Object} scope The scope of the effect function
11401  * @cfg {String} easing A valid Easing value for the effect
11402  * @cfg {String} afterCls A css class to apply after the effect
11403  * @cfg {Number} duration The length of time (in seconds) that the effect should last
11404  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
11405  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
11406  * effects that end with the element being visually hidden, ignored otherwise)
11407  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
11408  * a function which returns such a specification that will be applied to the Element after the effect finishes
11409  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
11410  * @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
11411  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
11412  */
11413 Roo.Fx = {
11414         /**
11415          * Slides the element into view.  An anchor point can be optionally passed to set the point of
11416          * origin for the slide effect.  This function automatically handles wrapping the element with
11417          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
11418          * Usage:
11419          *<pre><code>
11420 // default: slide the element in from the top
11421 el.slideIn();
11422
11423 // custom: slide the element in from the right with a 2-second duration
11424 el.slideIn('r', { duration: 2 });
11425
11426 // common config options shown with default values
11427 el.slideIn('t', {
11428     easing: 'easeOut',
11429     duration: .5
11430 });
11431 </code></pre>
11432          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
11433          * @param {Object} options (optional) Object literal with any of the Fx config options
11434          * @return {Roo.Element} The Element
11435          */
11436     slideIn : function(anchor, o){
11437         var el = this.getFxEl();
11438         o = o || {};
11439
11440         el.queueFx(o, function(){
11441
11442             anchor = anchor || "t";
11443
11444             // fix display to visibility
11445             this.fixDisplay();
11446
11447             // restore values after effect
11448             var r = this.getFxRestore();
11449             var b = this.getBox();
11450             // fixed size for slide
11451             this.setSize(b);
11452
11453             // wrap if needed
11454             var wrap = this.fxWrap(r.pos, o, "hidden");
11455
11456             var st = this.dom.style;
11457             st.visibility = "visible";
11458             st.position = "absolute";
11459
11460             // clear out temp styles after slide and unwrap
11461             var after = function(){
11462                 el.fxUnwrap(wrap, r.pos, o);
11463                 st.width = r.width;
11464                 st.height = r.height;
11465                 el.afterFx(o);
11466             };
11467             // time to calc the positions
11468             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
11469
11470             switch(anchor.toLowerCase()){
11471                 case "t":
11472                     wrap.setSize(b.width, 0);
11473                     st.left = st.bottom = "0";
11474                     a = {height: bh};
11475                 break;
11476                 case "l":
11477                     wrap.setSize(0, b.height);
11478                     st.right = st.top = "0";
11479                     a = {width: bw};
11480                 break;
11481                 case "r":
11482                     wrap.setSize(0, b.height);
11483                     wrap.setX(b.right);
11484                     st.left = st.top = "0";
11485                     a = {width: bw, points: pt};
11486                 break;
11487                 case "b":
11488                     wrap.setSize(b.width, 0);
11489                     wrap.setY(b.bottom);
11490                     st.left = st.top = "0";
11491                     a = {height: bh, points: pt};
11492                 break;
11493                 case "tl":
11494                     wrap.setSize(0, 0);
11495                     st.right = st.bottom = "0";
11496                     a = {width: bw, height: bh};
11497                 break;
11498                 case "bl":
11499                     wrap.setSize(0, 0);
11500                     wrap.setY(b.y+b.height);
11501                     st.right = st.top = "0";
11502                     a = {width: bw, height: bh, points: pt};
11503                 break;
11504                 case "br":
11505                     wrap.setSize(0, 0);
11506                     wrap.setXY([b.right, b.bottom]);
11507                     st.left = st.top = "0";
11508                     a = {width: bw, height: bh, points: pt};
11509                 break;
11510                 case "tr":
11511                     wrap.setSize(0, 0);
11512                     wrap.setX(b.x+b.width);
11513                     st.left = st.bottom = "0";
11514                     a = {width: bw, height: bh, points: pt};
11515                 break;
11516             }
11517             this.dom.style.visibility = "visible";
11518             wrap.show();
11519
11520             arguments.callee.anim = wrap.fxanim(a,
11521                 o,
11522                 'motion',
11523                 .5,
11524                 'easeOut', after);
11525         });
11526         return this;
11527     },
11528     
11529         /**
11530          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
11531          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
11532          * 'hidden') but block elements will still take up space in the document.  The element must be removed
11533          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
11534          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
11535          * Usage:
11536          *<pre><code>
11537 // default: slide the element out to the top
11538 el.slideOut();
11539
11540 // custom: slide the element out to the right with a 2-second duration
11541 el.slideOut('r', { duration: 2 });
11542
11543 // common config options shown with default values
11544 el.slideOut('t', {
11545     easing: 'easeOut',
11546     duration: .5,
11547     remove: false,
11548     useDisplay: false
11549 });
11550 </code></pre>
11551          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
11552          * @param {Object} options (optional) Object literal with any of the Fx config options
11553          * @return {Roo.Element} The Element
11554          */
11555     slideOut : function(anchor, o){
11556         var el = this.getFxEl();
11557         o = o || {};
11558
11559         el.queueFx(o, function(){
11560
11561             anchor = anchor || "t";
11562
11563             // restore values after effect
11564             var r = this.getFxRestore();
11565             
11566             var b = this.getBox();
11567             // fixed size for slide
11568             this.setSize(b);
11569
11570             // wrap if needed
11571             var wrap = this.fxWrap(r.pos, o, "visible");
11572
11573             var st = this.dom.style;
11574             st.visibility = "visible";
11575             st.position = "absolute";
11576
11577             wrap.setSize(b);
11578
11579             var after = function(){
11580                 if(o.useDisplay){
11581                     el.setDisplayed(false);
11582                 }else{
11583                     el.hide();
11584                 }
11585
11586                 el.fxUnwrap(wrap, r.pos, o);
11587
11588                 st.width = r.width;
11589                 st.height = r.height;
11590
11591                 el.afterFx(o);
11592             };
11593
11594             var a, zero = {to: 0};
11595             switch(anchor.toLowerCase()){
11596                 case "t":
11597                     st.left = st.bottom = "0";
11598                     a = {height: zero};
11599                 break;
11600                 case "l":
11601                     st.right = st.top = "0";
11602                     a = {width: zero};
11603                 break;
11604                 case "r":
11605                     st.left = st.top = "0";
11606                     a = {width: zero, points: {to:[b.right, b.y]}};
11607                 break;
11608                 case "b":
11609                     st.left = st.top = "0";
11610                     a = {height: zero, points: {to:[b.x, b.bottom]}};
11611                 break;
11612                 case "tl":
11613                     st.right = st.bottom = "0";
11614                     a = {width: zero, height: zero};
11615                 break;
11616                 case "bl":
11617                     st.right = st.top = "0";
11618                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
11619                 break;
11620                 case "br":
11621                     st.left = st.top = "0";
11622                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
11623                 break;
11624                 case "tr":
11625                     st.left = st.bottom = "0";
11626                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
11627                 break;
11628             }
11629
11630             arguments.callee.anim = wrap.fxanim(a,
11631                 o,
11632                 'motion',
11633                 .5,
11634                 "easeOut", after);
11635         });
11636         return this;
11637     },
11638
11639         /**
11640          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
11641          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
11642          * The element must be removed from the DOM using the 'remove' config option if desired.
11643          * Usage:
11644          *<pre><code>
11645 // default
11646 el.puff();
11647
11648 // common config options shown with default values
11649 el.puff({
11650     easing: 'easeOut',
11651     duration: .5,
11652     remove: false,
11653     useDisplay: false
11654 });
11655 </code></pre>
11656          * @param {Object} options (optional) Object literal with any of the Fx config options
11657          * @return {Roo.Element} The Element
11658          */
11659     puff : function(o){
11660         var el = this.getFxEl();
11661         o = o || {};
11662
11663         el.queueFx(o, function(){
11664             this.clearOpacity();
11665             this.show();
11666
11667             // restore values after effect
11668             var r = this.getFxRestore();
11669             var st = this.dom.style;
11670
11671             var after = function(){
11672                 if(o.useDisplay){
11673                     el.setDisplayed(false);
11674                 }else{
11675                     el.hide();
11676                 }
11677
11678                 el.clearOpacity();
11679
11680                 el.setPositioning(r.pos);
11681                 st.width = r.width;
11682                 st.height = r.height;
11683                 st.fontSize = '';
11684                 el.afterFx(o);
11685             };
11686
11687             var width = this.getWidth();
11688             var height = this.getHeight();
11689
11690             arguments.callee.anim = this.fxanim({
11691                     width : {to: this.adjustWidth(width * 2)},
11692                     height : {to: this.adjustHeight(height * 2)},
11693                     points : {by: [-(width * .5), -(height * .5)]},
11694                     opacity : {to: 0},
11695                     fontSize: {to:200, unit: "%"}
11696                 },
11697                 o,
11698                 'motion',
11699                 .5,
11700                 "easeOut", after);
11701         });
11702         return this;
11703     },
11704
11705         /**
11706          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
11707          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
11708          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
11709          * Usage:
11710          *<pre><code>
11711 // default
11712 el.switchOff();
11713
11714 // all config options shown with default values
11715 el.switchOff({
11716     easing: 'easeIn',
11717     duration: .3,
11718     remove: false,
11719     useDisplay: false
11720 });
11721 </code></pre>
11722          * @param {Object} options (optional) Object literal with any of the Fx config options
11723          * @return {Roo.Element} The Element
11724          */
11725     switchOff : function(o){
11726         var el = this.getFxEl();
11727         o = o || {};
11728
11729         el.queueFx(o, function(){
11730             this.clearOpacity();
11731             this.clip();
11732
11733             // restore values after effect
11734             var r = this.getFxRestore();
11735             var st = this.dom.style;
11736
11737             var after = function(){
11738                 if(o.useDisplay){
11739                     el.setDisplayed(false);
11740                 }else{
11741                     el.hide();
11742                 }
11743
11744                 el.clearOpacity();
11745                 el.setPositioning(r.pos);
11746                 st.width = r.width;
11747                 st.height = r.height;
11748
11749                 el.afterFx(o);
11750             };
11751
11752             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
11753                 this.clearOpacity();
11754                 (function(){
11755                     this.fxanim({
11756                         height:{to:1},
11757                         points:{by:[0, this.getHeight() * .5]}
11758                     }, o, 'motion', 0.3, 'easeIn', after);
11759                 }).defer(100, this);
11760             });
11761         });
11762         return this;
11763     },
11764
11765     /**
11766      * Highlights the Element by setting a color (applies to the background-color by default, but can be
11767      * changed using the "attr" config option) and then fading back to the original color. If no original
11768      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
11769      * Usage:
11770 <pre><code>
11771 // default: highlight background to yellow
11772 el.highlight();
11773
11774 // custom: highlight foreground text to blue for 2 seconds
11775 el.highlight("0000ff", { attr: 'color', duration: 2 });
11776
11777 // common config options shown with default values
11778 el.highlight("ffff9c", {
11779     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
11780     endColor: (current color) or "ffffff",
11781     easing: 'easeIn',
11782     duration: 1
11783 });
11784 </code></pre>
11785      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
11786      * @param {Object} options (optional) Object literal with any of the Fx config options
11787      * @return {Roo.Element} The Element
11788      */ 
11789     highlight : function(color, o){
11790         var el = this.getFxEl();
11791         o = o || {};
11792
11793         el.queueFx(o, function(){
11794             color = color || "ffff9c";
11795             attr = o.attr || "backgroundColor";
11796
11797             this.clearOpacity();
11798             this.show();
11799
11800             var origColor = this.getColor(attr);
11801             var restoreColor = this.dom.style[attr];
11802             endColor = (o.endColor || origColor) || "ffffff";
11803
11804             var after = function(){
11805                 el.dom.style[attr] = restoreColor;
11806                 el.afterFx(o);
11807             };
11808
11809             var a = {};
11810             a[attr] = {from: color, to: endColor};
11811             arguments.callee.anim = this.fxanim(a,
11812                 o,
11813                 'color',
11814                 1,
11815                 'easeIn', after);
11816         });
11817         return this;
11818     },
11819
11820    /**
11821     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
11822     * Usage:
11823 <pre><code>
11824 // default: a single light blue ripple
11825 el.frame();
11826
11827 // custom: 3 red ripples lasting 3 seconds total
11828 el.frame("ff0000", 3, { duration: 3 });
11829
11830 // common config options shown with default values
11831 el.frame("C3DAF9", 1, {
11832     duration: 1 //duration of entire animation (not each individual ripple)
11833     // Note: Easing is not configurable and will be ignored if included
11834 });
11835 </code></pre>
11836     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
11837     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
11838     * @param {Object} options (optional) Object literal with any of the Fx config options
11839     * @return {Roo.Element} The Element
11840     */
11841     frame : function(color, count, o){
11842         var el = this.getFxEl();
11843         o = o || {};
11844
11845         el.queueFx(o, function(){
11846             color = color || "#C3DAF9";
11847             if(color.length == 6){
11848                 color = "#" + color;
11849             }
11850             count = count || 1;
11851             duration = o.duration || 1;
11852             this.show();
11853
11854             var b = this.getBox();
11855             var animFn = function(){
11856                 var proxy = this.createProxy({
11857
11858                      style:{
11859                         visbility:"hidden",
11860                         position:"absolute",
11861                         "z-index":"35000", // yee haw
11862                         border:"0px solid " + color
11863                      }
11864                   });
11865                 var scale = Roo.isBorderBox ? 2 : 1;
11866                 proxy.animate({
11867                     top:{from:b.y, to:b.y - 20},
11868                     left:{from:b.x, to:b.x - 20},
11869                     borderWidth:{from:0, to:10},
11870                     opacity:{from:1, to:0},
11871                     height:{from:b.height, to:(b.height + (20*scale))},
11872                     width:{from:b.width, to:(b.width + (20*scale))}
11873                 }, duration, function(){
11874                     proxy.remove();
11875                 });
11876                 if(--count > 0){
11877                      animFn.defer((duration/2)*1000, this);
11878                 }else{
11879                     el.afterFx(o);
11880                 }
11881             };
11882             animFn.call(this);
11883         });
11884         return this;
11885     },
11886
11887    /**
11888     * Creates a pause before any subsequent queued effects begin.  If there are
11889     * no effects queued after the pause it will have no effect.
11890     * Usage:
11891 <pre><code>
11892 el.pause(1);
11893 </code></pre>
11894     * @param {Number} seconds The length of time to pause (in seconds)
11895     * @return {Roo.Element} The Element
11896     */
11897     pause : function(seconds){
11898         var el = this.getFxEl();
11899         var o = {};
11900
11901         el.queueFx(o, function(){
11902             setTimeout(function(){
11903                 el.afterFx(o);
11904             }, seconds * 1000);
11905         });
11906         return this;
11907     },
11908
11909    /**
11910     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
11911     * using the "endOpacity" config option.
11912     * Usage:
11913 <pre><code>
11914 // default: fade in from opacity 0 to 100%
11915 el.fadeIn();
11916
11917 // custom: fade in from opacity 0 to 75% over 2 seconds
11918 el.fadeIn({ endOpacity: .75, duration: 2});
11919
11920 // common config options shown with default values
11921 el.fadeIn({
11922     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
11923     easing: 'easeOut',
11924     duration: .5
11925 });
11926 </code></pre>
11927     * @param {Object} options (optional) Object literal with any of the Fx config options
11928     * @return {Roo.Element} The Element
11929     */
11930     fadeIn : function(o){
11931         var el = this.getFxEl();
11932         o = o || {};
11933         el.queueFx(o, function(){
11934             this.setOpacity(0);
11935             this.fixDisplay();
11936             this.dom.style.visibility = 'visible';
11937             var to = o.endOpacity || 1;
11938             arguments.callee.anim = this.fxanim({opacity:{to:to}},
11939                 o, null, .5, "easeOut", function(){
11940                 if(to == 1){
11941                     this.clearOpacity();
11942                 }
11943                 el.afterFx(o);
11944             });
11945         });
11946         return this;
11947     },
11948
11949    /**
11950     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
11951     * using the "endOpacity" config option.
11952     * Usage:
11953 <pre><code>
11954 // default: fade out from the element's current opacity to 0
11955 el.fadeOut();
11956
11957 // custom: fade out from the element's current opacity to 25% over 2 seconds
11958 el.fadeOut({ endOpacity: .25, duration: 2});
11959
11960 // common config options shown with default values
11961 el.fadeOut({
11962     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
11963     easing: 'easeOut',
11964     duration: .5
11965     remove: false,
11966     useDisplay: false
11967 });
11968 </code></pre>
11969     * @param {Object} options (optional) Object literal with any of the Fx config options
11970     * @return {Roo.Element} The Element
11971     */
11972     fadeOut : function(o){
11973         var el = this.getFxEl();
11974         o = o || {};
11975         el.queueFx(o, function(){
11976             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
11977                 o, null, .5, "easeOut", function(){
11978                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
11979                      this.dom.style.display = "none";
11980                 }else{
11981                      this.dom.style.visibility = "hidden";
11982                 }
11983                 this.clearOpacity();
11984                 el.afterFx(o);
11985             });
11986         });
11987         return this;
11988     },
11989
11990    /**
11991     * Animates the transition of an element's dimensions from a starting height/width
11992     * to an ending height/width.
11993     * Usage:
11994 <pre><code>
11995 // change height and width to 100x100 pixels
11996 el.scale(100, 100);
11997
11998 // common config options shown with default values.  The height and width will default to
11999 // the element's existing values if passed as null.
12000 el.scale(
12001     [element's width],
12002     [element's height], {
12003     easing: 'easeOut',
12004     duration: .35
12005 });
12006 </code></pre>
12007     * @param {Number} width  The new width (pass undefined to keep the original width)
12008     * @param {Number} height  The new height (pass undefined to keep the original height)
12009     * @param {Object} options (optional) Object literal with any of the Fx config options
12010     * @return {Roo.Element} The Element
12011     */
12012     scale : function(w, h, o){
12013         this.shift(Roo.apply({}, o, {
12014             width: w,
12015             height: h
12016         }));
12017         return this;
12018     },
12019
12020    /**
12021     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
12022     * Any of these properties not specified in the config object will not be changed.  This effect 
12023     * requires that at least one new dimension, position or opacity setting must be passed in on
12024     * the config object in order for the function to have any effect.
12025     * Usage:
12026 <pre><code>
12027 // slide the element horizontally to x position 200 while changing the height and opacity
12028 el.shift({ x: 200, height: 50, opacity: .8 });
12029
12030 // common config options shown with default values.
12031 el.shift({
12032     width: [element's width],
12033     height: [element's height],
12034     x: [element's x position],
12035     y: [element's y position],
12036     opacity: [element's opacity],
12037     easing: 'easeOut',
12038     duration: .35
12039 });
12040 </code></pre>
12041     * @param {Object} options  Object literal with any of the Fx config options
12042     * @return {Roo.Element} The Element
12043     */
12044     shift : function(o){
12045         var el = this.getFxEl();
12046         o = o || {};
12047         el.queueFx(o, function(){
12048             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
12049             if(w !== undefined){
12050                 a.width = {to: this.adjustWidth(w)};
12051             }
12052             if(h !== undefined){
12053                 a.height = {to: this.adjustHeight(h)};
12054             }
12055             if(x !== undefined || y !== undefined){
12056                 a.points = {to: [
12057                     x !== undefined ? x : this.getX(),
12058                     y !== undefined ? y : this.getY()
12059                 ]};
12060             }
12061             if(op !== undefined){
12062                 a.opacity = {to: op};
12063             }
12064             if(o.xy !== undefined){
12065                 a.points = {to: o.xy};
12066             }
12067             arguments.callee.anim = this.fxanim(a,
12068                 o, 'motion', .35, "easeOut", function(){
12069                 el.afterFx(o);
12070             });
12071         });
12072         return this;
12073     },
12074
12075         /**
12076          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
12077          * ending point of the effect.
12078          * Usage:
12079          *<pre><code>
12080 // default: slide the element downward while fading out
12081 el.ghost();
12082
12083 // custom: slide the element out to the right with a 2-second duration
12084 el.ghost('r', { duration: 2 });
12085
12086 // common config options shown with default values
12087 el.ghost('b', {
12088     easing: 'easeOut',
12089     duration: .5
12090     remove: false,
12091     useDisplay: false
12092 });
12093 </code></pre>
12094          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
12095          * @param {Object} options (optional) Object literal with any of the Fx config options
12096          * @return {Roo.Element} The Element
12097          */
12098     ghost : function(anchor, o){
12099         var el = this.getFxEl();
12100         o = o || {};
12101
12102         el.queueFx(o, function(){
12103             anchor = anchor || "b";
12104
12105             // restore values after effect
12106             var r = this.getFxRestore();
12107             var w = this.getWidth(),
12108                 h = this.getHeight();
12109
12110             var st = this.dom.style;
12111
12112             var after = function(){
12113                 if(o.useDisplay){
12114                     el.setDisplayed(false);
12115                 }else{
12116                     el.hide();
12117                 }
12118
12119                 el.clearOpacity();
12120                 el.setPositioning(r.pos);
12121                 st.width = r.width;
12122                 st.height = r.height;
12123
12124                 el.afterFx(o);
12125             };
12126
12127             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
12128             switch(anchor.toLowerCase()){
12129                 case "t":
12130                     pt.by = [0, -h];
12131                 break;
12132                 case "l":
12133                     pt.by = [-w, 0];
12134                 break;
12135                 case "r":
12136                     pt.by = [w, 0];
12137                 break;
12138                 case "b":
12139                     pt.by = [0, h];
12140                 break;
12141                 case "tl":
12142                     pt.by = [-w, -h];
12143                 break;
12144                 case "bl":
12145                     pt.by = [-w, h];
12146                 break;
12147                 case "br":
12148                     pt.by = [w, h];
12149                 break;
12150                 case "tr":
12151                     pt.by = [w, -h];
12152                 break;
12153             }
12154
12155             arguments.callee.anim = this.fxanim(a,
12156                 o,
12157                 'motion',
12158                 .5,
12159                 "easeOut", after);
12160         });
12161         return this;
12162     },
12163
12164         /**
12165          * Ensures that all effects queued after syncFx is called on the element are
12166          * run concurrently.  This is the opposite of {@link #sequenceFx}.
12167          * @return {Roo.Element} The Element
12168          */
12169     syncFx : function(){
12170         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
12171             block : false,
12172             concurrent : true,
12173             stopFx : false
12174         });
12175         return this;
12176     },
12177
12178         /**
12179          * Ensures that all effects queued after sequenceFx is called on the element are
12180          * run in sequence.  This is the opposite of {@link #syncFx}.
12181          * @return {Roo.Element} The Element
12182          */
12183     sequenceFx : function(){
12184         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
12185             block : false,
12186             concurrent : false,
12187             stopFx : false
12188         });
12189         return this;
12190     },
12191
12192         /* @private */
12193     nextFx : function(){
12194         var ef = this.fxQueue[0];
12195         if(ef){
12196             ef.call(this);
12197         }
12198     },
12199
12200         /**
12201          * Returns true if the element has any effects actively running or queued, else returns false.
12202          * @return {Boolean} True if element has active effects, else false
12203          */
12204     hasActiveFx : function(){
12205         return this.fxQueue && this.fxQueue[0];
12206     },
12207
12208         /**
12209          * Stops any running effects and clears the element's internal effects queue if it contains
12210          * any additional effects that haven't started yet.
12211          * @return {Roo.Element} The Element
12212          */
12213     stopFx : function(){
12214         if(this.hasActiveFx()){
12215             var cur = this.fxQueue[0];
12216             if(cur && cur.anim && cur.anim.isAnimated()){
12217                 this.fxQueue = [cur]; // clear out others
12218                 cur.anim.stop(true);
12219             }
12220         }
12221         return this;
12222     },
12223
12224         /* @private */
12225     beforeFx : function(o){
12226         if(this.hasActiveFx() && !o.concurrent){
12227            if(o.stopFx){
12228                this.stopFx();
12229                return true;
12230            }
12231            return false;
12232         }
12233         return true;
12234     },
12235
12236         /**
12237          * Returns true if the element is currently blocking so that no other effect can be queued
12238          * until this effect is finished, else returns false if blocking is not set.  This is commonly
12239          * used to ensure that an effect initiated by a user action runs to completion prior to the
12240          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
12241          * @return {Boolean} True if blocking, else false
12242          */
12243     hasFxBlock : function(){
12244         var q = this.fxQueue;
12245         return q && q[0] && q[0].block;
12246     },
12247
12248         /* @private */
12249     queueFx : function(o, fn){
12250         if(!this.fxQueue){
12251             this.fxQueue = [];
12252         }
12253         if(!this.hasFxBlock()){
12254             Roo.applyIf(o, this.fxDefaults);
12255             if(!o.concurrent){
12256                 var run = this.beforeFx(o);
12257                 fn.block = o.block;
12258                 this.fxQueue.push(fn);
12259                 if(run){
12260                     this.nextFx();
12261                 }
12262             }else{
12263                 fn.call(this);
12264             }
12265         }
12266         return this;
12267     },
12268
12269         /* @private */
12270     fxWrap : function(pos, o, vis){
12271         var wrap;
12272         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
12273             var wrapXY;
12274             if(o.fixPosition){
12275                 wrapXY = this.getXY();
12276             }
12277             var div = document.createElement("div");
12278             div.style.visibility = vis;
12279             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
12280             wrap.setPositioning(pos);
12281             if(wrap.getStyle("position") == "static"){
12282                 wrap.position("relative");
12283             }
12284             this.clearPositioning('auto');
12285             wrap.clip();
12286             wrap.dom.appendChild(this.dom);
12287             if(wrapXY){
12288                 wrap.setXY(wrapXY);
12289             }
12290         }
12291         return wrap;
12292     },
12293
12294         /* @private */
12295     fxUnwrap : function(wrap, pos, o){
12296         this.clearPositioning();
12297         this.setPositioning(pos);
12298         if(!o.wrap){
12299             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
12300             wrap.remove();
12301         }
12302     },
12303
12304         /* @private */
12305     getFxRestore : function(){
12306         var st = this.dom.style;
12307         return {pos: this.getPositioning(), width: st.width, height : st.height};
12308     },
12309
12310         /* @private */
12311     afterFx : function(o){
12312         if(o.afterStyle){
12313             this.applyStyles(o.afterStyle);
12314         }
12315         if(o.afterCls){
12316             this.addClass(o.afterCls);
12317         }
12318         if(o.remove === true){
12319             this.remove();
12320         }
12321         Roo.callback(o.callback, o.scope, [this]);
12322         if(!o.concurrent){
12323             this.fxQueue.shift();
12324             this.nextFx();
12325         }
12326     },
12327
12328         /* @private */
12329     getFxEl : function(){ // support for composite element fx
12330         return Roo.get(this.dom);
12331     },
12332
12333         /* @private */
12334     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
12335         animType = animType || 'run';
12336         opt = opt || {};
12337         var anim = Roo.lib.Anim[animType](
12338             this.dom, args,
12339             (opt.duration || defaultDur) || .35,
12340             (opt.easing || defaultEase) || 'easeOut',
12341             function(){
12342                 Roo.callback(cb, this);
12343             },
12344             this
12345         );
12346         opt.anim = anim;
12347         return anim;
12348     }
12349 };
12350
12351 // backwords compat
12352 Roo.Fx.resize = Roo.Fx.scale;
12353
12354 //When included, Roo.Fx is automatically applied to Element so that all basic
12355 //effects are available directly via the Element API
12356 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
12357  * Based on:
12358  * Ext JS Library 1.1.1
12359  * Copyright(c) 2006-2007, Ext JS, LLC.
12360  *
12361  * Originally Released Under LGPL - original licence link has changed is not relivant.
12362  *
12363  * Fork - LGPL
12364  * <script type="text/javascript">
12365  */
12366
12367
12368 /**
12369  * @class Roo.CompositeElement
12370  * Standard composite class. Creates a Roo.Element for every element in the collection.
12371  * <br><br>
12372  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
12373  * actions will be performed on all the elements in this collection.</b>
12374  * <br><br>
12375  * All methods return <i>this</i> and can be chained.
12376  <pre><code>
12377  var els = Roo.select("#some-el div.some-class", true);
12378  // or select directly from an existing element
12379  var el = Roo.get('some-el');
12380  el.select('div.some-class', true);
12381
12382  els.setWidth(100); // all elements become 100 width
12383  els.hide(true); // all elements fade out and hide
12384  // or
12385  els.setWidth(100).hide(true);
12386  </code></pre>
12387  */
12388 Roo.CompositeElement = function(els){
12389     this.elements = [];
12390     this.addElements(els);
12391 };
12392 Roo.CompositeElement.prototype = {
12393     isComposite: true,
12394     addElements : function(els){
12395         if(!els) {
12396             return this;
12397         }
12398         if(typeof els == "string"){
12399             els = Roo.Element.selectorFunction(els);
12400         }
12401         var yels = this.elements;
12402         var index = yels.length-1;
12403         for(var i = 0, len = els.length; i < len; i++) {
12404                 yels[++index] = Roo.get(els[i]);
12405         }
12406         return this;
12407     },
12408
12409     /**
12410     * Clears this composite and adds the elements returned by the passed selector.
12411     * @param {String/Array} els A string CSS selector, an array of elements or an element
12412     * @return {CompositeElement} this
12413     */
12414     fill : function(els){
12415         this.elements = [];
12416         this.add(els);
12417         return this;
12418     },
12419
12420     /**
12421     * Filters this composite to only elements that match the passed selector.
12422     * @param {String} selector A string CSS selector
12423     * @param {Boolean} inverse return inverse filter (not matches)
12424     * @return {CompositeElement} this
12425     */
12426     filter : function(selector, inverse){
12427         var els = [];
12428         inverse = inverse || false;
12429         this.each(function(el){
12430             var match = inverse ? !el.is(selector) : el.is(selector);
12431             if(match){
12432                 els[els.length] = el.dom;
12433             }
12434         });
12435         this.fill(els);
12436         return this;
12437     },
12438
12439     invoke : function(fn, args){
12440         var els = this.elements;
12441         for(var i = 0, len = els.length; i < len; i++) {
12442                 Roo.Element.prototype[fn].apply(els[i], args);
12443         }
12444         return this;
12445     },
12446     /**
12447     * Adds elements to this composite.
12448     * @param {String/Array} els A string CSS selector, an array of elements or an element
12449     * @return {CompositeElement} this
12450     */
12451     add : function(els){
12452         if(typeof els == "string"){
12453             this.addElements(Roo.Element.selectorFunction(els));
12454         }else if(els.length !== undefined){
12455             this.addElements(els);
12456         }else{
12457             this.addElements([els]);
12458         }
12459         return this;
12460     },
12461     /**
12462     * Calls the passed function passing (el, this, index) for each element in this composite.
12463     * @param {Function} fn The function to call
12464     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
12465     * @return {CompositeElement} this
12466     */
12467     each : function(fn, scope){
12468         var els = this.elements;
12469         for(var i = 0, len = els.length; i < len; i++){
12470             if(fn.call(scope || els[i], els[i], this, i) === false) {
12471                 break;
12472             }
12473         }
12474         return this;
12475     },
12476
12477     /**
12478      * Returns the Element object at the specified index
12479      * @param {Number} index
12480      * @return {Roo.Element}
12481      */
12482     item : function(index){
12483         return this.elements[index] || null;
12484     },
12485
12486     /**
12487      * Returns the first Element
12488      * @return {Roo.Element}
12489      */
12490     first : function(){
12491         return this.item(0);
12492     },
12493
12494     /**
12495      * Returns the last Element
12496      * @return {Roo.Element}
12497      */
12498     last : function(){
12499         return this.item(this.elements.length-1);
12500     },
12501
12502     /**
12503      * Returns the number of elements in this composite
12504      * @return Number
12505      */
12506     getCount : function(){
12507         return this.elements.length;
12508     },
12509
12510     /**
12511      * Returns true if this composite contains the passed element
12512      * @return Boolean
12513      */
12514     contains : function(el){
12515         return this.indexOf(el) !== -1;
12516     },
12517
12518     /**
12519      * Returns true if this composite contains the passed element
12520      * @return Boolean
12521      */
12522     indexOf : function(el){
12523         return this.elements.indexOf(Roo.get(el));
12524     },
12525
12526
12527     /**
12528     * Removes the specified element(s).
12529     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
12530     * or an array of any of those.
12531     * @param {Boolean} removeDom (optional) True to also remove the element from the document
12532     * @return {CompositeElement} this
12533     */
12534     removeElement : function(el, removeDom){
12535         if(el instanceof Array){
12536             for(var i = 0, len = el.length; i < len; i++){
12537                 this.removeElement(el[i]);
12538             }
12539             return this;
12540         }
12541         var index = typeof el == 'number' ? el : this.indexOf(el);
12542         if(index !== -1){
12543             if(removeDom){
12544                 var d = this.elements[index];
12545                 if(d.dom){
12546                     d.remove();
12547                 }else{
12548                     d.parentNode.removeChild(d);
12549                 }
12550             }
12551             this.elements.splice(index, 1);
12552         }
12553         return this;
12554     },
12555
12556     /**
12557     * Replaces the specified element with the passed element.
12558     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
12559     * to replace.
12560     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
12561     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
12562     * @return {CompositeElement} this
12563     */
12564     replaceElement : function(el, replacement, domReplace){
12565         var index = typeof el == 'number' ? el : this.indexOf(el);
12566         if(index !== -1){
12567             if(domReplace){
12568                 this.elements[index].replaceWith(replacement);
12569             }else{
12570                 this.elements.splice(index, 1, Roo.get(replacement))
12571             }
12572         }
12573         return this;
12574     },
12575
12576     /**
12577      * Removes all elements.
12578      */
12579     clear : function(){
12580         this.elements = [];
12581     }
12582 };
12583 (function(){
12584     Roo.CompositeElement.createCall = function(proto, fnName){
12585         if(!proto[fnName]){
12586             proto[fnName] = function(){
12587                 return this.invoke(fnName, arguments);
12588             };
12589         }
12590     };
12591     for(var fnName in Roo.Element.prototype){
12592         if(typeof Roo.Element.prototype[fnName] == "function"){
12593             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
12594         }
12595     };
12596 })();
12597 /*
12598  * Based on:
12599  * Ext JS Library 1.1.1
12600  * Copyright(c) 2006-2007, Ext JS, LLC.
12601  *
12602  * Originally Released Under LGPL - original licence link has changed is not relivant.
12603  *
12604  * Fork - LGPL
12605  * <script type="text/javascript">
12606  */
12607
12608 /**
12609  * @class Roo.CompositeElementLite
12610  * @extends Roo.CompositeElement
12611  * Flyweight composite class. Reuses the same Roo.Element for element operations.
12612  <pre><code>
12613  var els = Roo.select("#some-el div.some-class");
12614  // or select directly from an existing element
12615  var el = Roo.get('some-el');
12616  el.select('div.some-class');
12617
12618  els.setWidth(100); // all elements become 100 width
12619  els.hide(true); // all elements fade out and hide
12620  // or
12621  els.setWidth(100).hide(true);
12622  </code></pre><br><br>
12623  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
12624  * actions will be performed on all the elements in this collection.</b>
12625  */
12626 Roo.CompositeElementLite = function(els){
12627     Roo.CompositeElementLite.superclass.constructor.call(this, els);
12628     this.el = new Roo.Element.Flyweight();
12629 };
12630 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
12631     addElements : function(els){
12632         if(els){
12633             if(els instanceof Array){
12634                 this.elements = this.elements.concat(els);
12635             }else{
12636                 var yels = this.elements;
12637                 var index = yels.length-1;
12638                 for(var i = 0, len = els.length; i < len; i++) {
12639                     yels[++index] = els[i];
12640                 }
12641             }
12642         }
12643         return this;
12644     },
12645     invoke : function(fn, args){
12646         var els = this.elements;
12647         var el = this.el;
12648         for(var i = 0, len = els.length; i < len; i++) {
12649             el.dom = els[i];
12650                 Roo.Element.prototype[fn].apply(el, args);
12651         }
12652         return this;
12653     },
12654     /**
12655      * Returns a flyweight Element of the dom element object at the specified index
12656      * @param {Number} index
12657      * @return {Roo.Element}
12658      */
12659     item : function(index){
12660         if(!this.elements[index]){
12661             return null;
12662         }
12663         this.el.dom = this.elements[index];
12664         return this.el;
12665     },
12666
12667     // fixes scope with flyweight
12668     addListener : function(eventName, handler, scope, opt){
12669         var els = this.elements;
12670         for(var i = 0, len = els.length; i < len; i++) {
12671             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
12672         }
12673         return this;
12674     },
12675
12676     /**
12677     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
12678     * passed is the flyweight (shared) Roo.Element instance, so if you require a
12679     * a reference to the dom node, use el.dom.</b>
12680     * @param {Function} fn The function to call
12681     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
12682     * @return {CompositeElement} this
12683     */
12684     each : function(fn, scope){
12685         var els = this.elements;
12686         var el = this.el;
12687         for(var i = 0, len = els.length; i < len; i++){
12688             el.dom = els[i];
12689                 if(fn.call(scope || el, el, this, i) === false){
12690                 break;
12691             }
12692         }
12693         return this;
12694     },
12695
12696     indexOf : function(el){
12697         return this.elements.indexOf(Roo.getDom(el));
12698     },
12699
12700     replaceElement : function(el, replacement, domReplace){
12701         var index = typeof el == 'number' ? el : this.indexOf(el);
12702         if(index !== -1){
12703             replacement = Roo.getDom(replacement);
12704             if(domReplace){
12705                 var d = this.elements[index];
12706                 d.parentNode.insertBefore(replacement, d);
12707                 d.parentNode.removeChild(d);
12708             }
12709             this.elements.splice(index, 1, replacement);
12710         }
12711         return this;
12712     }
12713 });
12714 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
12715
12716 /*
12717  * Based on:
12718  * Ext JS Library 1.1.1
12719  * Copyright(c) 2006-2007, Ext JS, LLC.
12720  *
12721  * Originally Released Under LGPL - original licence link has changed is not relivant.
12722  *
12723  * Fork - LGPL
12724  * <script type="text/javascript">
12725  */
12726
12727  
12728
12729 /**
12730  * @class Roo.data.Connection
12731  * @extends Roo.util.Observable
12732  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
12733  * either to a configured URL, or to a URL specified at request time. 
12734  * 
12735  * Requests made by this class are asynchronous, and will return immediately. No data from
12736  * the server will be available to the statement immediately following the {@link #request} call.
12737  * To process returned data, use a callback in the request options object, or an event listener.
12738  * 
12739  * Note: If you are doing a file upload, you will not get a normal response object sent back to
12740  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
12741  * The response object is created using the innerHTML of the IFRAME's document as the responseText
12742  * property and, if present, the IFRAME's XML document as the responseXML property.
12743  * 
12744  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
12745  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
12746  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
12747  * standard DOM methods.
12748  * @constructor
12749  * @param {Object} config a configuration object.
12750  */
12751 Roo.data.Connection = function(config){
12752     Roo.apply(this, config);
12753     this.addEvents({
12754         /**
12755          * @event beforerequest
12756          * Fires before a network request is made to retrieve a data object.
12757          * @param {Connection} conn This Connection object.
12758          * @param {Object} options The options config object passed to the {@link #request} method.
12759          */
12760         "beforerequest" : true,
12761         /**
12762          * @event requestcomplete
12763          * Fires if the request was successfully completed.
12764          * @param {Connection} conn This Connection object.
12765          * @param {Object} response The XHR object containing the response data.
12766          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
12767          * @param {Object} options The options config object passed to the {@link #request} method.
12768          */
12769         "requestcomplete" : true,
12770         /**
12771          * @event requestexception
12772          * Fires if an error HTTP status was returned from the server.
12773          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
12774          * @param {Connection} conn This Connection object.
12775          * @param {Object} response The XHR object containing the response data.
12776          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
12777          * @param {Object} options The options config object passed to the {@link #request} method.
12778          */
12779         "requestexception" : true
12780     });
12781     Roo.data.Connection.superclass.constructor.call(this);
12782 };
12783
12784 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
12785     /**
12786      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12787      */
12788     /**
12789      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12790      * extra parameters to each request made by this object. (defaults to undefined)
12791      */
12792     /**
12793      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12794      *  to each request made by this object. (defaults to undefined)
12795      */
12796     /**
12797      * @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)
12798      */
12799     /**
12800      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12801      */
12802     timeout : 30000,
12803     /**
12804      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12805      * @type Boolean
12806      */
12807     autoAbort:false,
12808
12809     /**
12810      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12811      * @type Boolean
12812      */
12813     disableCaching: true,
12814
12815     /**
12816      * Sends an HTTP request to a remote server.
12817      * @param {Object} options An object which may contain the following properties:<ul>
12818      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
12819      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
12820      * request, a url encoded string or a function to call to get either.</li>
12821      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
12822      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
12823      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
12824      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
12825      * <li>options {Object} The parameter to the request call.</li>
12826      * <li>success {Boolean} True if the request succeeded.</li>
12827      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
12828      * </ul></li>
12829      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
12830      * The callback is passed the following parameters:<ul>
12831      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
12832      * <li>options {Object} The parameter to the request call.</li>
12833      * </ul></li>
12834      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
12835      * The callback is passed the following parameters:<ul>
12836      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
12837      * <li>options {Object} The parameter to the request call.</li>
12838      * </ul></li>
12839      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
12840      * for the callback function. Defaults to the browser window.</li>
12841      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
12842      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
12843      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
12844      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
12845      * params for the post data. Any params will be appended to the URL.</li>
12846      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
12847      * </ul>
12848      * @return {Number} transactionId
12849      */
12850     request : function(o){
12851         if(this.fireEvent("beforerequest", this, o) !== false){
12852             var p = o.params;
12853
12854             if(typeof p == "function"){
12855                 p = p.call(o.scope||window, o);
12856             }
12857             if(typeof p == "object"){
12858                 p = Roo.urlEncode(o.params);
12859             }
12860             if(this.extraParams){
12861                 var extras = Roo.urlEncode(this.extraParams);
12862                 p = p ? (p + '&' + extras) : extras;
12863             }
12864
12865             var url = o.url || this.url;
12866             if(typeof url == 'function'){
12867                 url = url.call(o.scope||window, o);
12868             }
12869
12870             if(o.form){
12871                 var form = Roo.getDom(o.form);
12872                 url = url || form.action;
12873
12874                 var enctype = form.getAttribute("enctype");
12875                 
12876                 if (o.formData) {
12877                     return this.doFormDataUpload(o, url);
12878                 }
12879                 
12880                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
12881                     return this.doFormUpload(o, p, url);
12882                 }
12883                 var f = Roo.lib.Ajax.serializeForm(form);
12884                 p = p ? (p + '&' + f) : f;
12885             }
12886             
12887             if (!o.form && o.formData) {
12888                 o.formData = o.formData === true ? new FormData() : o.formData;
12889                 for (var k in o.params) {
12890                     o.formData.append(k,o.params[k]);
12891                 }
12892                     
12893                 return this.doFormDataUpload(o, url);
12894             }
12895             
12896
12897             var hs = o.headers;
12898             if(this.defaultHeaders){
12899                 hs = Roo.apply(hs || {}, this.defaultHeaders);
12900                 if(!o.headers){
12901                     o.headers = hs;
12902                 }
12903             }
12904
12905             var cb = {
12906                 success: this.handleResponse,
12907                 failure: this.handleFailure,
12908                 scope: this,
12909                 argument: {options: o},
12910                 timeout : o.timeout || this.timeout
12911             };
12912
12913             var method = o.method||this.method||(p ? "POST" : "GET");
12914
12915             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
12916                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
12917             }
12918
12919             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
12920                 if(o.autoAbort){
12921                     this.abort();
12922                 }
12923             }else if(this.autoAbort !== false){
12924                 this.abort();
12925             }
12926
12927             if((method == 'GET' && p) || o.xmlData){
12928                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
12929                 p = '';
12930             }
12931             Roo.lib.Ajax.useDefaultHeader = typeof(o.headers) == 'undefined' || typeof(o.headers['Content-Type']) == 'undefined';
12932             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
12933             Roo.lib.Ajax.useDefaultHeader == true;
12934             return this.transId;
12935         }else{
12936             Roo.callback(o.callback, o.scope, [o, null, null]);
12937             return null;
12938         }
12939     },
12940
12941     /**
12942      * Determine whether this object has a request outstanding.
12943      * @param {Number} transactionId (Optional) defaults to the last transaction
12944      * @return {Boolean} True if there is an outstanding request.
12945      */
12946     isLoading : function(transId){
12947         if(transId){
12948             return Roo.lib.Ajax.isCallInProgress(transId);
12949         }else{
12950             return this.transId ? true : false;
12951         }
12952     },
12953
12954     /**
12955      * Aborts any outstanding request.
12956      * @param {Number} transactionId (Optional) defaults to the last transaction
12957      */
12958     abort : function(transId){
12959         if(transId || this.isLoading()){
12960             Roo.lib.Ajax.abort(transId || this.transId);
12961         }
12962     },
12963
12964     // private
12965     handleResponse : function(response){
12966         this.transId = false;
12967         var options = response.argument.options;
12968         response.argument = options ? options.argument : null;
12969         this.fireEvent("requestcomplete", this, response, options);
12970         Roo.callback(options.success, options.scope, [response, options]);
12971         Roo.callback(options.callback, options.scope, [options, true, response]);
12972     },
12973
12974     // private
12975     handleFailure : function(response, e){
12976         this.transId = false;
12977         var options = response.argument.options;
12978         response.argument = options ? options.argument : null;
12979         this.fireEvent("requestexception", this, response, options, e);
12980         Roo.callback(options.failure, options.scope, [response, options]);
12981         Roo.callback(options.callback, options.scope, [options, false, response]);
12982     },
12983
12984     // private
12985     doFormUpload : function(o, ps, url){
12986         var id = Roo.id();
12987         var frame = document.createElement('iframe');
12988         frame.id = id;
12989         frame.name = id;
12990         frame.className = 'x-hidden';
12991         if(Roo.isIE){
12992             frame.src = Roo.SSL_SECURE_URL;
12993         }
12994         document.body.appendChild(frame);
12995
12996         if(Roo.isIE){
12997            document.frames[id].name = id;
12998         }
12999
13000         var form = Roo.getDom(o.form);
13001         form.target = id;
13002         form.method = 'POST';
13003         form.enctype = form.encoding = 'multipart/form-data';
13004         if(url){
13005             form.action = url;
13006         }
13007
13008         var hiddens, hd;
13009         if(ps){ // add dynamic params
13010             hiddens = [];
13011             ps = Roo.urlDecode(ps, false);
13012             for(var k in ps){
13013                 if(ps.hasOwnProperty(k)){
13014                     hd = document.createElement('input');
13015                     hd.type = 'hidden';
13016                     hd.name = k;
13017                     hd.value = ps[k];
13018                     form.appendChild(hd);
13019                     hiddens.push(hd);
13020                 }
13021             }
13022         }
13023
13024         function cb(){
13025             var r = {  // bogus response object
13026                 responseText : '',
13027                 responseXML : null
13028             };
13029
13030             r.argument = o ? o.argument : null;
13031
13032             try { //
13033                 var doc;
13034                 if(Roo.isIE){
13035                     doc = frame.contentWindow.document;
13036                 }else {
13037                     doc = (frame.contentDocument || window.frames[id].document);
13038                 }
13039                 if(doc && doc.body){
13040                     r.responseText = doc.body.innerHTML;
13041                 }
13042                 if(doc && doc.XMLDocument){
13043                     r.responseXML = doc.XMLDocument;
13044                 }else {
13045                     r.responseXML = doc;
13046                 }
13047             }
13048             catch(e) {
13049                 // ignore
13050             }
13051
13052             Roo.EventManager.removeListener(frame, 'load', cb, this);
13053
13054             this.fireEvent("requestcomplete", this, r, o);
13055             Roo.callback(o.success, o.scope, [r, o]);
13056             Roo.callback(o.callback, o.scope, [o, true, r]);
13057
13058             setTimeout(function(){document.body.removeChild(frame);}, 100);
13059         }
13060
13061         Roo.EventManager.on(frame, 'load', cb, this);
13062         form.submit();
13063
13064         if(hiddens){ // remove dynamic params
13065             for(var i = 0, len = hiddens.length; i < len; i++){
13066                 form.removeChild(hiddens[i]);
13067             }
13068         }
13069     },
13070     // this is a 'formdata version???'
13071     
13072     
13073     doFormDataUpload : function(o,  url)
13074     {
13075         var formData;
13076         if (o.form) {
13077             var form =  Roo.getDom(o.form);
13078             form.enctype = form.encoding = 'multipart/form-data';
13079             formData = o.formData === true ? new FormData(form) : o.formData;
13080         } else {
13081             formData = o.formData === true ? new FormData() : o.formData;
13082         }
13083         
13084       
13085         var cb = {
13086             success: this.handleResponse,
13087             failure: this.handleFailure,
13088             scope: this,
13089             argument: {options: o},
13090             timeout : o.timeout || this.timeout
13091         };
13092  
13093         if(typeof o.autoAbort == 'boolean'){ // options gets top priority
13094             if(o.autoAbort){
13095                 this.abort();
13096             }
13097         }else if(this.autoAbort !== false){
13098             this.abort();
13099         }
13100
13101         //Roo.lib.Ajax.defaultPostHeader = null;
13102         Roo.lib.Ajax.useDefaultHeader = false;
13103         this.transId = Roo.lib.Ajax.request( "POST", url, cb,  formData, o);
13104         Roo.lib.Ajax.useDefaultHeader = true;
13105  
13106          
13107     }
13108     
13109 });
13110 /*
13111  * Based on:
13112  * Ext JS Library 1.1.1
13113  * Copyright(c) 2006-2007, Ext JS, LLC.
13114  *
13115  * Originally Released Under LGPL - original licence link has changed is not relivant.
13116  *
13117  * Fork - LGPL
13118  * <script type="text/javascript">
13119  */
13120  
13121 /**
13122  * Global Ajax request class.
13123  * 
13124  * @class Roo.Ajax
13125  * @extends Roo.data.Connection
13126  * @static
13127  * 
13128  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
13129  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
13130  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
13131  * @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)
13132  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
13133  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
13134  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
13135  */
13136 Roo.Ajax = new Roo.data.Connection({
13137     // fix up the docs
13138     /**
13139      * @scope Roo.Ajax
13140      * @type {Boolear} 
13141      */
13142     autoAbort : false,
13143
13144     /**
13145      * Serialize the passed form into a url encoded string
13146      * @scope Roo.Ajax
13147      * @param {String/HTMLElement} form
13148      * @return {String}
13149      */
13150     serializeForm : function(form){
13151         return Roo.lib.Ajax.serializeForm(form);
13152     }
13153 });/*
13154  * Based on:
13155  * Ext JS Library 1.1.1
13156  * Copyright(c) 2006-2007, Ext JS, LLC.
13157  *
13158  * Originally Released Under LGPL - original licence link has changed is not relivant.
13159  *
13160  * Fork - LGPL
13161  * <script type="text/javascript">
13162  */
13163
13164  
13165 /**
13166  * @class Roo.UpdateManager
13167  * @extends Roo.util.Observable
13168  * Provides AJAX-style update for Element object.<br><br>
13169  * Usage:<br>
13170  * <pre><code>
13171  * // Get it from a Roo.Element object
13172  * var el = Roo.get("foo");
13173  * var mgr = el.getUpdateManager();
13174  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
13175  * ...
13176  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
13177  * <br>
13178  * // or directly (returns the same UpdateManager instance)
13179  * var mgr = new Roo.UpdateManager("myElementId");
13180  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
13181  * mgr.on("update", myFcnNeedsToKnow);
13182  * <br>
13183    // short handed call directly from the element object
13184    Roo.get("foo").load({
13185         url: "bar.php",
13186         scripts:true,
13187         params: "for=bar",
13188         text: "Loading Foo..."
13189    });
13190  * </code></pre>
13191  * @constructor
13192  * Create new UpdateManager directly.
13193  * @param {String/HTMLElement/Roo.Element} el The element to update
13194  * @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).
13195  */
13196 Roo.UpdateManager = function(el, forceNew){
13197     el = Roo.get(el);
13198     if(!forceNew && el.updateManager){
13199         return el.updateManager;
13200     }
13201     /**
13202      * The Element object
13203      * @type Roo.Element
13204      */
13205     this.el = el;
13206     /**
13207      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
13208      * @type String
13209      */
13210     this.defaultUrl = null;
13211
13212     this.addEvents({
13213         /**
13214          * @event beforeupdate
13215          * Fired before an update is made, return false from your handler and the update is cancelled.
13216          * @param {Roo.Element} el
13217          * @param {String/Object/Function} url
13218          * @param {String/Object} params
13219          */
13220         "beforeupdate": true,
13221         /**
13222          * @event update
13223          * Fired after successful update is made.
13224          * @param {Roo.Element} el
13225          * @param {Object} oResponseObject The response Object
13226          */
13227         "update": true,
13228         /**
13229          * @event failure
13230          * Fired on update failure.
13231          * @param {Roo.Element} el
13232          * @param {Object} oResponseObject The response Object
13233          */
13234         "failure": true
13235     });
13236     var d = Roo.UpdateManager.defaults;
13237     /**
13238      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
13239      * @type String
13240      */
13241     this.sslBlankUrl = d.sslBlankUrl;
13242     /**
13243      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
13244      * @type Boolean
13245      */
13246     this.disableCaching = d.disableCaching;
13247     /**
13248      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
13249      * @type String
13250      */
13251     this.indicatorText = d.indicatorText;
13252     /**
13253      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
13254      * @type String
13255      */
13256     this.showLoadIndicator = d.showLoadIndicator;
13257     /**
13258      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
13259      * @type Number
13260      */
13261     this.timeout = d.timeout;
13262
13263     /**
13264      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
13265      * @type Boolean
13266      */
13267     this.loadScripts = d.loadScripts;
13268
13269     /**
13270      * Transaction object of current executing transaction
13271      */
13272     this.transaction = null;
13273
13274     /**
13275      * @private
13276      */
13277     this.autoRefreshProcId = null;
13278     /**
13279      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
13280      * @type Function
13281      */
13282     this.refreshDelegate = this.refresh.createDelegate(this);
13283     /**
13284      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
13285      * @type Function
13286      */
13287     this.updateDelegate = this.update.createDelegate(this);
13288     /**
13289      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
13290      * @type Function
13291      */
13292     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
13293     /**
13294      * @private
13295      */
13296     this.successDelegate = this.processSuccess.createDelegate(this);
13297     /**
13298      * @private
13299      */
13300     this.failureDelegate = this.processFailure.createDelegate(this);
13301
13302     if(!this.renderer){
13303      /**
13304       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
13305       */
13306     this.renderer = new Roo.UpdateManager.BasicRenderer();
13307     }
13308     
13309     Roo.UpdateManager.superclass.constructor.call(this);
13310 };
13311
13312 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
13313     /**
13314      * Get the Element this UpdateManager is bound to
13315      * @return {Roo.Element} The element
13316      */
13317     getEl : function(){
13318         return this.el;
13319     },
13320     /**
13321      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
13322      * @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:
13323 <pre><code>
13324 um.update({<br/>
13325     url: "your-url.php",<br/>
13326     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
13327     callback: yourFunction,<br/>
13328     scope: yourObject, //(optional scope)  <br/>
13329     discardUrl: false, <br/>
13330     nocache: false,<br/>
13331     text: "Loading...",<br/>
13332     timeout: 30,<br/>
13333     scripts: false<br/>
13334 });
13335 </code></pre>
13336      * The only required property is url. The optional properties nocache, text and scripts
13337      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
13338      * @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}
13339      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
13340      * @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.
13341      */
13342     update : function(url, params, callback, discardUrl){
13343         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
13344             var method = this.method,
13345                 cfg;
13346             if(typeof url == "object"){ // must be config object
13347                 cfg = url;
13348                 url = cfg.url;
13349                 params = params || cfg.params;
13350                 callback = callback || cfg.callback;
13351                 discardUrl = discardUrl || cfg.discardUrl;
13352                 if(callback && cfg.scope){
13353                     callback = callback.createDelegate(cfg.scope);
13354                 }
13355                 if(typeof cfg.method != "undefined"){method = cfg.method;};
13356                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
13357                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
13358                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
13359                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
13360             }
13361             this.showLoading();
13362             if(!discardUrl){
13363                 this.defaultUrl = url;
13364             }
13365             if(typeof url == "function"){
13366                 url = url.call(this);
13367             }
13368
13369             method = method || (params ? "POST" : "GET");
13370             if(method == "GET"){
13371                 url = this.prepareUrl(url);
13372             }
13373
13374             var o = Roo.apply(cfg ||{}, {
13375                 url : url,
13376                 params: params,
13377                 success: this.successDelegate,
13378                 failure: this.failureDelegate,
13379                 callback: undefined,
13380                 timeout: (this.timeout*1000),
13381                 argument: {"url": url, "form": null, "callback": callback, "params": params}
13382             });
13383             Roo.log("updated manager called with timeout of " + o.timeout);
13384             this.transaction = Roo.Ajax.request(o);
13385         }
13386     },
13387
13388     /**
13389      * 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.
13390      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
13391      * @param {String/HTMLElement} form The form Id or form element
13392      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
13393      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
13394      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
13395      */
13396     formUpdate : function(form, url, reset, callback){
13397         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
13398             if(typeof url == "function"){
13399                 url = url.call(this);
13400             }
13401             form = Roo.getDom(form);
13402             this.transaction = Roo.Ajax.request({
13403                 form: form,
13404                 url:url,
13405                 success: this.successDelegate,
13406                 failure: this.failureDelegate,
13407                 timeout: (this.timeout*1000),
13408                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
13409             });
13410             this.showLoading.defer(1, this);
13411         }
13412     },
13413
13414     /**
13415      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
13416      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
13417      */
13418     refresh : function(callback){
13419         if(this.defaultUrl == null){
13420             return;
13421         }
13422         this.update(this.defaultUrl, null, callback, true);
13423     },
13424
13425     /**
13426      * Set this element to auto refresh.
13427      * @param {Number} interval How often to update (in seconds).
13428      * @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)
13429      * @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}
13430      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
13431      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
13432      */
13433     startAutoRefresh : function(interval, url, params, callback, refreshNow){
13434         if(refreshNow){
13435             this.update(url || this.defaultUrl, params, callback, true);
13436         }
13437         if(this.autoRefreshProcId){
13438             clearInterval(this.autoRefreshProcId);
13439         }
13440         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
13441     },
13442
13443     /**
13444      * Stop auto refresh on this element.
13445      */
13446      stopAutoRefresh : function(){
13447         if(this.autoRefreshProcId){
13448             clearInterval(this.autoRefreshProcId);
13449             delete this.autoRefreshProcId;
13450         }
13451     },
13452
13453     isAutoRefreshing : function(){
13454        return this.autoRefreshProcId ? true : false;
13455     },
13456     /**
13457      * Called to update the element to "Loading" state. Override to perform custom action.
13458      */
13459     showLoading : function(){
13460         if(this.showLoadIndicator){
13461             this.el.update(this.indicatorText);
13462         }
13463     },
13464
13465     /**
13466      * Adds unique parameter to query string if disableCaching = true
13467      * @private
13468      */
13469     prepareUrl : function(url){
13470         if(this.disableCaching){
13471             var append = "_dc=" + (new Date().getTime());
13472             if(url.indexOf("?") !== -1){
13473                 url += "&" + append;
13474             }else{
13475                 url += "?" + append;
13476             }
13477         }
13478         return url;
13479     },
13480
13481     /**
13482      * @private
13483      */
13484     processSuccess : function(response){
13485         this.transaction = null;
13486         if(response.argument.form && response.argument.reset){
13487             try{ // put in try/catch since some older FF releases had problems with this
13488                 response.argument.form.reset();
13489             }catch(e){}
13490         }
13491         if(this.loadScripts){
13492             this.renderer.render(this.el, response, this,
13493                 this.updateComplete.createDelegate(this, [response]));
13494         }else{
13495             this.renderer.render(this.el, response, this);
13496             this.updateComplete(response);
13497         }
13498     },
13499
13500     updateComplete : function(response){
13501         this.fireEvent("update", this.el, response);
13502         if(typeof response.argument.callback == "function"){
13503             response.argument.callback(this.el, true, response);
13504         }
13505     },
13506
13507     /**
13508      * @private
13509      */
13510     processFailure : function(response){
13511         this.transaction = null;
13512         this.fireEvent("failure", this.el, response);
13513         if(typeof response.argument.callback == "function"){
13514             response.argument.callback(this.el, false, response);
13515         }
13516     },
13517
13518     /**
13519      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
13520      * @param {Object} renderer The object implementing the render() method
13521      */
13522     setRenderer : function(renderer){
13523         this.renderer = renderer;
13524     },
13525
13526     getRenderer : function(){
13527        return this.renderer;
13528     },
13529
13530     /**
13531      * Set the defaultUrl used for updates
13532      * @param {String/Function} defaultUrl The url or a function to call to get the url
13533      */
13534     setDefaultUrl : function(defaultUrl){
13535         this.defaultUrl = defaultUrl;
13536     },
13537
13538     /**
13539      * Aborts the executing transaction
13540      */
13541     abort : function(){
13542         if(this.transaction){
13543             Roo.Ajax.abort(this.transaction);
13544         }
13545     },
13546
13547     /**
13548      * Returns true if an update is in progress
13549      * @return {Boolean}
13550      */
13551     isUpdating : function(){
13552         if(this.transaction){
13553             return Roo.Ajax.isLoading(this.transaction);
13554         }
13555         return false;
13556     }
13557 });
13558
13559 /**
13560  * @class Roo.UpdateManager.defaults
13561  * @static (not really - but it helps the doc tool)
13562  * The defaults collection enables customizing the default properties of UpdateManager
13563  */
13564    Roo.UpdateManager.defaults = {
13565        /**
13566          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
13567          * @type Number
13568          */
13569          timeout : 30,
13570
13571          /**
13572          * True to process scripts by default (Defaults to false).
13573          * @type Boolean
13574          */
13575         loadScripts : false,
13576
13577         /**
13578         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
13579         * @type String
13580         */
13581         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
13582         /**
13583          * Whether to append unique parameter on get request to disable caching (Defaults to false).
13584          * @type Boolean
13585          */
13586         disableCaching : false,
13587         /**
13588          * Whether to show indicatorText when loading (Defaults to true).
13589          * @type Boolean
13590          */
13591         showLoadIndicator : true,
13592         /**
13593          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
13594          * @type String
13595          */
13596         indicatorText : '<div class="loading-indicator">Loading...</div>'
13597    };
13598
13599 /**
13600  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
13601  *Usage:
13602  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
13603  * @param {String/HTMLElement/Roo.Element} el The element to update
13604  * @param {String} url The url
13605  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
13606  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
13607  * @static
13608  * @deprecated
13609  * @member Roo.UpdateManager
13610  */
13611 Roo.UpdateManager.updateElement = function(el, url, params, options){
13612     var um = Roo.get(el, true).getUpdateManager();
13613     Roo.apply(um, options);
13614     um.update(url, params, options ? options.callback : null);
13615 };
13616 // alias for backwards compat
13617 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
13618 /**
13619  * @class Roo.UpdateManager.BasicRenderer
13620  * Default Content renderer. Updates the elements innerHTML with the responseText.
13621  */
13622 Roo.UpdateManager.BasicRenderer = function(){};
13623
13624 Roo.UpdateManager.BasicRenderer.prototype = {
13625     /**
13626      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
13627      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
13628      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
13629      * @param {Roo.Element} el The element being rendered
13630      * @param {Object} response The YUI Connect response object
13631      * @param {UpdateManager} updateManager The calling update manager
13632      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
13633      */
13634      render : function(el, response, updateManager, callback){
13635         el.update(response.responseText, updateManager.loadScripts, callback);
13636     }
13637 };
13638 /*
13639  * Based on:
13640  * Roo JS
13641  * (c)) Alan Knowles
13642  * Licence : LGPL
13643  */
13644
13645
13646 /**
13647  * @class Roo.DomTemplate
13648  * @extends Roo.Template
13649  * An effort at a dom based template engine..
13650  *
13651  * Similar to XTemplate, except it uses dom parsing to create the template..
13652  *
13653  * Supported features:
13654  *
13655  *  Tags:
13656
13657 <pre><code>
13658       {a_variable} - output encoded.
13659       {a_variable.format:("Y-m-d")} - call a method on the variable
13660       {a_variable:raw} - unencoded output
13661       {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
13662       {a_variable:this.method_on_template(...)} - call a method on the template object.
13663  
13664 </code></pre>
13665  *  The tpl tag:
13666 <pre><code>
13667         &lt;div roo-for="a_variable or condition.."&gt;&lt;/div&gt;
13668         &lt;div roo-if="a_variable or condition"&gt;&lt;/div&gt;
13669         &lt;div roo-exec="some javascript"&gt;&lt;/div&gt;
13670         &lt;div roo-name="named_template"&gt;&lt;/div&gt; 
13671   
13672 </code></pre>
13673  *      
13674  */
13675 Roo.DomTemplate = function()
13676 {
13677      Roo.DomTemplate.superclass.constructor.apply(this, arguments);
13678      if (this.html) {
13679         this.compile();
13680      }
13681 };
13682
13683
13684 Roo.extend(Roo.DomTemplate, Roo.Template, {
13685     /**
13686      * id counter for sub templates.
13687      */
13688     id : 0,
13689     /**
13690      * flag to indicate if dom parser is inside a pre,
13691      * it will strip whitespace if not.
13692      */
13693     inPre : false,
13694     
13695     /**
13696      * The various sub templates
13697      */
13698     tpls : false,
13699     
13700     
13701     
13702     /**
13703      *
13704      * basic tag replacing syntax
13705      * WORD:WORD()
13706      *
13707      * // you can fake an object call by doing this
13708      *  x.t:(test,tesT) 
13709      * 
13710      */
13711     re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
13712     //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
13713     
13714     iterChild : function (node, method) {
13715         
13716         var oldPre = this.inPre;
13717         if (node.tagName == 'PRE') {
13718             this.inPre = true;
13719         }
13720         for( var i = 0; i < node.childNodes.length; i++) {
13721             method.call(this, node.childNodes[i]);
13722         }
13723         this.inPre = oldPre;
13724     },
13725     
13726     
13727     
13728     /**
13729      * compile the template
13730      *
13731      * This is not recursive, so I'm not sure how nested templates are really going to be handled..
13732      *
13733      */
13734     compile: function()
13735     {
13736         var s = this.html;
13737         
13738         // covert the html into DOM...
13739         var doc = false;
13740         var div =false;
13741         try {
13742             doc = document.implementation.createHTMLDocument("");
13743             doc.documentElement.innerHTML =   this.html  ;
13744             div = doc.documentElement;
13745         } catch (e) {
13746             // old IE... - nasty -- it causes all sorts of issues.. with
13747             // images getting pulled from server..
13748             div = document.createElement('div');
13749             div.innerHTML = this.html;
13750         }
13751         //doc.documentElement.innerHTML = htmlBody
13752          
13753         
13754         
13755         this.tpls = [];
13756         var _t = this;
13757         this.iterChild(div, function(n) {_t.compileNode(n, true); });
13758         
13759         var tpls = this.tpls;
13760         
13761         // create a top level template from the snippet..
13762         
13763         //Roo.log(div.innerHTML);
13764         
13765         var tpl = {
13766             uid : 'master',
13767             id : this.id++,
13768             attr : false,
13769             value : false,
13770             body : div.innerHTML,
13771             
13772             forCall : false,
13773             execCall : false,
13774             dom : div,
13775             isTop : true
13776             
13777         };
13778         tpls.unshift(tpl);
13779         
13780         
13781         // compile them...
13782         this.tpls = [];
13783         Roo.each(tpls, function(tp){
13784             this.compileTpl(tp);
13785             this.tpls[tp.id] = tp;
13786         }, this);
13787         
13788         this.master = tpls[0];
13789         return this;
13790         
13791         
13792     },
13793     
13794     compileNode : function(node, istop) {
13795         // test for
13796         //Roo.log(node);
13797         
13798         
13799         // skip anything not a tag..
13800         if (node.nodeType != 1) {
13801             if (node.nodeType == 3 && !this.inPre) {
13802                 // reduce white space..
13803                 node.nodeValue = node.nodeValue.replace(/\s+/g, ' '); 
13804                 
13805             }
13806             return;
13807         }
13808         
13809         var tpl = {
13810             uid : false,
13811             id : false,
13812             attr : false,
13813             value : false,
13814             body : '',
13815             
13816             forCall : false,
13817             execCall : false,
13818             dom : false,
13819             isTop : istop
13820             
13821             
13822         };
13823         
13824         
13825         switch(true) {
13826             case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
13827             case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
13828             case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
13829             case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
13830             // no default..
13831         }
13832         
13833         
13834         if (!tpl.attr) {
13835             // just itterate children..
13836             this.iterChild(node,this.compileNode);
13837             return;
13838         }
13839         tpl.uid = this.id++;
13840         tpl.value = node.getAttribute('roo-' +  tpl.attr);
13841         node.removeAttribute('roo-'+ tpl.attr);
13842         if (tpl.attr != 'name') {
13843             var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
13844             node.parentNode.replaceChild(placeholder,  node);
13845         } else {
13846             
13847             var placeholder =  document.createElement('span');
13848             placeholder.className = 'roo-tpl-' + tpl.value;
13849             node.parentNode.replaceChild(placeholder,  node);
13850         }
13851         
13852         // parent now sees '{domtplXXXX}
13853         this.iterChild(node,this.compileNode);
13854         
13855         // we should now have node body...
13856         var div = document.createElement('div');
13857         div.appendChild(node);
13858         tpl.dom = node;
13859         // this has the unfortunate side effect of converting tagged attributes
13860         // eg. href="{...}" into %7C...%7D
13861         // this has been fixed by searching for those combo's although it's a bit hacky..
13862         
13863         
13864         tpl.body = div.innerHTML;
13865         
13866         
13867          
13868         tpl.id = tpl.uid;
13869         switch(tpl.attr) {
13870             case 'for' :
13871                 switch (tpl.value) {
13872                     case '.':  tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
13873                     case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
13874                     default:   tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
13875                 }
13876                 break;
13877             
13878             case 'exec':
13879                 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
13880                 break;
13881             
13882             case 'if':     
13883                 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
13884                 break;
13885             
13886             case 'name':
13887                 tpl.id  = tpl.value; // replace non characters???
13888                 break;
13889             
13890         }
13891         
13892         
13893         this.tpls.push(tpl);
13894         
13895         
13896         
13897     },
13898     
13899     
13900     
13901     
13902     /**
13903      * Compile a segment of the template into a 'sub-template'
13904      *
13905      * 
13906      * 
13907      *
13908      */
13909     compileTpl : function(tpl)
13910     {
13911         var fm = Roo.util.Format;
13912         var useF = this.disableFormats !== true;
13913         
13914         var sep = Roo.isGecko ? "+\n" : ",\n";
13915         
13916         var undef = function(str) {
13917             Roo.debug && Roo.log("Property not found :"  + str);
13918             return '';
13919         };
13920           
13921         //Roo.log(tpl.body);
13922         
13923         
13924         
13925         var fn = function(m, lbrace, name, format, args)
13926         {
13927             //Roo.log("ARGS");
13928             //Roo.log(arguments);
13929             args = args ? args.replace(/\\'/g,"'") : args;
13930             //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
13931             if (typeof(format) == 'undefined') {
13932                 format =  'htmlEncode'; 
13933             }
13934             if (format == 'raw' ) {
13935                 format = false;
13936             }
13937             
13938             if(name.substr(0, 6) == 'domtpl'){
13939                 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
13940             }
13941             
13942             // build an array of options to determine if value is undefined..
13943             
13944             // basically get 'xxxx.yyyy' then do
13945             // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
13946             //    (function () { Roo.log("Property not found"); return ''; })() :
13947             //    ......
13948             
13949             var udef_ar = [];
13950             var lookfor = '';
13951             Roo.each(name.split('.'), function(st) {
13952                 lookfor += (lookfor.length ? '.': '') + st;
13953                 udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
13954             });
13955             
13956             var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
13957             
13958             
13959             if(format && useF){
13960                 
13961                 args = args ? ',' + args : "";
13962                  
13963                 if(format.substr(0, 5) != "this."){
13964                     format = "fm." + format + '(';
13965                 }else{
13966                     format = 'this.call("'+ format.substr(5) + '", ';
13967                     args = ", values";
13968                 }
13969                 
13970                 return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
13971             }
13972              
13973             if (args && args.length) {
13974                 // called with xxyx.yuu:(test,test)
13975                 // change to ()
13976                 return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
13977             }
13978             // raw.. - :raw modifier..
13979             return "'"+ sep + udef_st  + name + ")"+sep+"'";
13980             
13981         };
13982         var body;
13983         // branched to use + in gecko and [].join() in others
13984         if(Roo.isGecko){
13985             body = "tpl.compiled = function(values, parent){  with(values) { return '" +
13986                    tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
13987                     "';};};";
13988         }else{
13989             body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
13990             body.push(tpl.body.replace(/(\r\n|\n)/g,
13991                             '\\n').replace(/'/g, "\\'").replace(this.re, fn));
13992             body.push("'].join('');};};");
13993             body = body.join('');
13994         }
13995         
13996         Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
13997        
13998         /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
13999         eval(body);
14000         
14001         return this;
14002     },
14003      
14004     /**
14005      * same as applyTemplate, except it's done to one of the subTemplates
14006      * when using named templates, you can do:
14007      *
14008      * var str = pl.applySubTemplate('your-name', values);
14009      *
14010      * 
14011      * @param {Number} id of the template
14012      * @param {Object} values to apply to template
14013      * @param {Object} parent (normaly the instance of this object)
14014      */
14015     applySubTemplate : function(id, values, parent)
14016     {
14017         
14018         
14019         var t = this.tpls[id];
14020         
14021         
14022         try { 
14023             if(t.ifCall && !t.ifCall.call(this, values, parent)){
14024                 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
14025                 return '';
14026             }
14027         } catch(e) {
14028             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
14029             Roo.log(values);
14030           
14031             return '';
14032         }
14033         try { 
14034             
14035             if(t.execCall && t.execCall.call(this, values, parent)){
14036                 return '';
14037             }
14038         } catch(e) {
14039             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
14040             Roo.log(values);
14041             return '';
14042         }
14043         
14044         try {
14045             var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
14046             parent = t.target ? values : parent;
14047             if(t.forCall && vs instanceof Array){
14048                 var buf = [];
14049                 for(var i = 0, len = vs.length; i < len; i++){
14050                     try {
14051                         buf[buf.length] = t.compiled.call(this, vs[i], parent);
14052                     } catch (e) {
14053                         Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
14054                         Roo.log(e.body);
14055                         //Roo.log(t.compiled);
14056                         Roo.log(vs[i]);
14057                     }   
14058                 }
14059                 return buf.join('');
14060             }
14061         } catch (e) {
14062             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
14063             Roo.log(values);
14064             return '';
14065         }
14066         try {
14067             return t.compiled.call(this, vs, parent);
14068         } catch (e) {
14069             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
14070             Roo.log(e.body);
14071             //Roo.log(t.compiled);
14072             Roo.log(values);
14073             return '';
14074         }
14075     },
14076
14077    
14078
14079     applyTemplate : function(values){
14080         return this.master.compiled.call(this, values, {});
14081         //var s = this.subs;
14082     },
14083
14084     apply : function(){
14085         return this.applyTemplate.apply(this, arguments);
14086     }
14087
14088  });
14089
14090 Roo.DomTemplate.from = function(el){
14091     el = Roo.getDom(el);
14092     return new Roo.Domtemplate(el.value || el.innerHTML);
14093 };/*
14094  * Based on:
14095  * Ext JS Library 1.1.1
14096  * Copyright(c) 2006-2007, Ext JS, LLC.
14097  *
14098  * Originally Released Under LGPL - original licence link has changed is not relivant.
14099  *
14100  * Fork - LGPL
14101  * <script type="text/javascript">
14102  */
14103
14104 /**
14105  * @class Roo.util.DelayedTask
14106  * Provides a convenient method of performing setTimeout where a new
14107  * timeout cancels the old timeout. An example would be performing validation on a keypress.
14108  * You can use this class to buffer
14109  * the keypress events for a certain number of milliseconds, and perform only if they stop
14110  * for that amount of time.
14111  * @constructor The parameters to this constructor serve as defaults and are not required.
14112  * @param {Function} fn (optional) The default function to timeout
14113  * @param {Object} scope (optional) The default scope of that timeout
14114  * @param {Array} args (optional) The default Array of arguments
14115  */
14116 Roo.util.DelayedTask = function(fn, scope, args){
14117     var id = null, d, t;
14118
14119     var call = function(){
14120         var now = new Date().getTime();
14121         if(now - t >= d){
14122             clearInterval(id);
14123             id = null;
14124             fn.apply(scope, args || []);
14125         }
14126     };
14127     /**
14128      * Cancels any pending timeout and queues a new one
14129      * @param {Number} delay The milliseconds to delay
14130      * @param {Function} newFn (optional) Overrides function passed to constructor
14131      * @param {Object} newScope (optional) Overrides scope passed to constructor
14132      * @param {Array} newArgs (optional) Overrides args passed to constructor
14133      */
14134     this.delay = function(delay, newFn, newScope, newArgs){
14135         if(id && delay != d){
14136             this.cancel();
14137         }
14138         d = delay;
14139         t = new Date().getTime();
14140         fn = newFn || fn;
14141         scope = newScope || scope;
14142         args = newArgs || args;
14143         if(!id){
14144             id = setInterval(call, d);
14145         }
14146     };
14147
14148     /**
14149      * Cancel the last queued timeout
14150      */
14151     this.cancel = function(){
14152         if(id){
14153             clearInterval(id);
14154             id = null;
14155         }
14156     };
14157 };/*
14158  * Based on:
14159  * Ext JS Library 1.1.1
14160  * Copyright(c) 2006-2007, Ext JS, LLC.
14161  *
14162  * Originally Released Under LGPL - original licence link has changed is not relivant.
14163  *
14164  * Fork - LGPL
14165  * <script type="text/javascript">
14166  */
14167 /**
14168  * @class Roo.util.TaskRunner
14169  * Manage background tasks - not sure why this is better that setInterval?
14170  * @static
14171  *
14172  */
14173  
14174 Roo.util.TaskRunner = function(interval){
14175     interval = interval || 10;
14176     var tasks = [], removeQueue = [];
14177     var id = 0;
14178     var running = false;
14179
14180     var stopThread = function(){
14181         running = false;
14182         clearInterval(id);
14183         id = 0;
14184     };
14185
14186     var startThread = function(){
14187         if(!running){
14188             running = true;
14189             id = setInterval(runTasks, interval);
14190         }
14191     };
14192
14193     var removeTask = function(task){
14194         removeQueue.push(task);
14195         if(task.onStop){
14196             task.onStop();
14197         }
14198     };
14199
14200     var runTasks = function(){
14201         if(removeQueue.length > 0){
14202             for(var i = 0, len = removeQueue.length; i < len; i++){
14203                 tasks.remove(removeQueue[i]);
14204             }
14205             removeQueue = [];
14206             if(tasks.length < 1){
14207                 stopThread();
14208                 return;
14209             }
14210         }
14211         var now = new Date().getTime();
14212         for(var i = 0, len = tasks.length; i < len; ++i){
14213             var t = tasks[i];
14214             var itime = now - t.taskRunTime;
14215             if(t.interval <= itime){
14216                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
14217                 t.taskRunTime = now;
14218                 if(rt === false || t.taskRunCount === t.repeat){
14219                     removeTask(t);
14220                     return;
14221                 }
14222             }
14223             if(t.duration && t.duration <= (now - t.taskStartTime)){
14224                 removeTask(t);
14225             }
14226         }
14227     };
14228
14229     /**
14230      * Queues a new task.
14231      * @param {Object} task
14232      *
14233      * Task property : interval = how frequent to run.
14234      * Task object should implement
14235      * function run()
14236      * Task object may implement
14237      * function onStop()
14238      */
14239     this.start = function(task){
14240         tasks.push(task);
14241         task.taskStartTime = new Date().getTime();
14242         task.taskRunTime = 0;
14243         task.taskRunCount = 0;
14244         startThread();
14245         return task;
14246     };
14247     /**
14248      * Stop  new task.
14249      * @param {Object} task
14250      */
14251     this.stop = function(task){
14252         removeTask(task);
14253         return task;
14254     };
14255     /**
14256      * Stop all Tasks
14257      */
14258     this.stopAll = function(){
14259         stopThread();
14260         for(var i = 0, len = tasks.length; i < len; i++){
14261             if(tasks[i].onStop){
14262                 tasks[i].onStop();
14263             }
14264         }
14265         tasks = [];
14266         removeQueue = [];
14267     };
14268 };
14269
14270 Roo.TaskMgr = new Roo.util.TaskRunner();/*
14271  * Based on:
14272  * Ext JS Library 1.1.1
14273  * Copyright(c) 2006-2007, Ext JS, LLC.
14274  *
14275  * Originally Released Under LGPL - original licence link has changed is not relivant.
14276  *
14277  * Fork - LGPL
14278  * <script type="text/javascript">
14279  */
14280
14281  
14282 /**
14283  * @class Roo.util.MixedCollection
14284  * @extends Roo.util.Observable
14285  * A Collection class that maintains both numeric indexes and keys and exposes events.
14286  * @constructor
14287  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
14288  * collection (defaults to false)
14289  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
14290  * and return the key value for that item.  This is used when available to look up the key on items that
14291  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
14292  * equivalent to providing an implementation for the {@link #getKey} method.
14293  */
14294 Roo.util.MixedCollection = function(allowFunctions, keyFn){
14295     this.items = [];
14296     this.map = {};
14297     this.keys = [];
14298     this.length = 0;
14299     this.addEvents({
14300         /**
14301          * @event clear
14302          * Fires when the collection is cleared.
14303          */
14304         "clear" : true,
14305         /**
14306          * @event add
14307          * Fires when an item is added to the collection.
14308          * @param {Number} index The index at which the item was added.
14309          * @param {Object} o The item added.
14310          * @param {String} key The key associated with the added item.
14311          */
14312         "add" : true,
14313         /**
14314          * @event replace
14315          * Fires when an item is replaced in the collection.
14316          * @param {String} key he key associated with the new added.
14317          * @param {Object} old The item being replaced.
14318          * @param {Object} new The new item.
14319          */
14320         "replace" : true,
14321         /**
14322          * @event remove
14323          * Fires when an item is removed from the collection.
14324          * @param {Object} o The item being removed.
14325          * @param {String} key (optional) The key associated with the removed item.
14326          */
14327         "remove" : true,
14328         "sort" : true
14329     });
14330     this.allowFunctions = allowFunctions === true;
14331     if(keyFn){
14332         this.getKey = keyFn;
14333     }
14334     Roo.util.MixedCollection.superclass.constructor.call(this);
14335 };
14336
14337 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
14338     allowFunctions : false,
14339     
14340 /**
14341  * Adds an item to the collection.
14342  * @param {String} key The key to associate with the item
14343  * @param {Object} o The item to add.
14344  * @return {Object} The item added.
14345  */
14346     add : function(key, o){
14347         if(arguments.length == 1){
14348             o = arguments[0];
14349             key = this.getKey(o);
14350         }
14351         if(typeof key == "undefined" || key === null){
14352             this.length++;
14353             this.items.push(o);
14354             this.keys.push(null);
14355         }else{
14356             var old = this.map[key];
14357             if(old){
14358                 return this.replace(key, o);
14359             }
14360             this.length++;
14361             this.items.push(o);
14362             this.map[key] = o;
14363             this.keys.push(key);
14364         }
14365         this.fireEvent("add", this.length-1, o, key);
14366         return o;
14367     },
14368        
14369 /**
14370   * MixedCollection has a generic way to fetch keys if you implement getKey.
14371 <pre><code>
14372 // normal way
14373 var mc = new Roo.util.MixedCollection();
14374 mc.add(someEl.dom.id, someEl);
14375 mc.add(otherEl.dom.id, otherEl);
14376 //and so on
14377
14378 // using getKey
14379 var mc = new Roo.util.MixedCollection();
14380 mc.getKey = function(el){
14381    return el.dom.id;
14382 };
14383 mc.add(someEl);
14384 mc.add(otherEl);
14385
14386 // or via the constructor
14387 var mc = new Roo.util.MixedCollection(false, function(el){
14388    return el.dom.id;
14389 });
14390 mc.add(someEl);
14391 mc.add(otherEl);
14392 </code></pre>
14393  * @param o {Object} The item for which to find the key.
14394  * @return {Object} The key for the passed item.
14395  */
14396     getKey : function(o){
14397          return o.id; 
14398     },
14399    
14400 /**
14401  * Replaces an item in the collection.
14402  * @param {String} key The key associated with the item to replace, or the item to replace.
14403  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
14404  * @return {Object}  The new item.
14405  */
14406     replace : function(key, o){
14407         if(arguments.length == 1){
14408             o = arguments[0];
14409             key = this.getKey(o);
14410         }
14411         var old = this.item(key);
14412         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
14413              return this.add(key, o);
14414         }
14415         var index = this.indexOfKey(key);
14416         this.items[index] = o;
14417         this.map[key] = o;
14418         this.fireEvent("replace", key, old, o);
14419         return o;
14420     },
14421    
14422 /**
14423  * Adds all elements of an Array or an Object to the collection.
14424  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
14425  * an Array of values, each of which are added to the collection.
14426  */
14427     addAll : function(objs){
14428         if(arguments.length > 1 || objs instanceof Array){
14429             var args = arguments.length > 1 ? arguments : objs;
14430             for(var i = 0, len = args.length; i < len; i++){
14431                 this.add(args[i]);
14432             }
14433         }else{
14434             for(var key in objs){
14435                 if(this.allowFunctions || typeof objs[key] != "function"){
14436                     this.add(key, objs[key]);
14437                 }
14438             }
14439         }
14440     },
14441    
14442 /**
14443  * Executes the specified function once for every item in the collection, passing each
14444  * item as the first and only parameter. returning false from the function will stop the iteration.
14445  * @param {Function} fn The function to execute for each item.
14446  * @param {Object} scope (optional) The scope in which to execute the function.
14447  */
14448     each : function(fn, scope){
14449         var items = [].concat(this.items); // each safe for removal
14450         for(var i = 0, len = items.length; i < len; i++){
14451             if(fn.call(scope || items[i], items[i], i, len) === false){
14452                 break;
14453             }
14454         }
14455     },
14456    
14457 /**
14458  * Executes the specified function once for every key in the collection, passing each
14459  * key, and its associated item as the first two parameters.
14460  * @param {Function} fn The function to execute for each item.
14461  * @param {Object} scope (optional) The scope in which to execute the function.
14462  */
14463     eachKey : function(fn, scope){
14464         for(var i = 0, len = this.keys.length; i < len; i++){
14465             fn.call(scope || window, this.keys[i], this.items[i], i, len);
14466         }
14467     },
14468    
14469 /**
14470  * Returns the first item in the collection which elicits a true return value from the
14471  * passed selection function.
14472  * @param {Function} fn The selection function to execute for each item.
14473  * @param {Object} scope (optional) The scope in which to execute the function.
14474  * @return {Object} The first item in the collection which returned true from the selection function.
14475  */
14476     find : function(fn, scope){
14477         for(var i = 0, len = this.items.length; i < len; i++){
14478             if(fn.call(scope || window, this.items[i], this.keys[i])){
14479                 return this.items[i];
14480             }
14481         }
14482         return null;
14483     },
14484    
14485 /**
14486  * Inserts an item at the specified index in the collection.
14487  * @param {Number} index The index to insert the item at.
14488  * @param {String} key The key to associate with the new item, or the item itself.
14489  * @param {Object} o  (optional) If the second parameter was a key, the new item.
14490  * @return {Object} The item inserted.
14491  */
14492     insert : function(index, key, o){
14493         if(arguments.length == 2){
14494             o = arguments[1];
14495             key = this.getKey(o);
14496         }
14497         if(index >= this.length){
14498             return this.add(key, o);
14499         }
14500         this.length++;
14501         this.items.splice(index, 0, o);
14502         if(typeof key != "undefined" && key != null){
14503             this.map[key] = o;
14504         }
14505         this.keys.splice(index, 0, key);
14506         this.fireEvent("add", index, o, key);
14507         return o;
14508     },
14509    
14510 /**
14511  * Removed an item from the collection.
14512  * @param {Object} o The item to remove.
14513  * @return {Object} The item removed.
14514  */
14515     remove : function(o){
14516         return this.removeAt(this.indexOf(o));
14517     },
14518    
14519 /**
14520  * Remove an item from a specified index in the collection.
14521  * @param {Number} index The index within the collection of the item to remove.
14522  */
14523     removeAt : function(index){
14524         if(index < this.length && index >= 0){
14525             this.length--;
14526             var o = this.items[index];
14527             this.items.splice(index, 1);
14528             var key = this.keys[index];
14529             if(typeof key != "undefined"){
14530                 delete this.map[key];
14531             }
14532             this.keys.splice(index, 1);
14533             this.fireEvent("remove", o, key);
14534         }
14535     },
14536    
14537 /**
14538  * Removed an item associated with the passed key fom the collection.
14539  * @param {String} key The key of the item to remove.
14540  */
14541     removeKey : function(key){
14542         return this.removeAt(this.indexOfKey(key));
14543     },
14544    
14545 /**
14546  * Returns the number of items in the collection.
14547  * @return {Number} the number of items in the collection.
14548  */
14549     getCount : function(){
14550         return this.length; 
14551     },
14552    
14553 /**
14554  * Returns index within the collection of the passed Object.
14555  * @param {Object} o The item to find the index of.
14556  * @return {Number} index of the item.
14557  */
14558     indexOf : function(o){
14559         if(!this.items.indexOf){
14560             for(var i = 0, len = this.items.length; i < len; i++){
14561                 if(this.items[i] == o) {
14562                     return i;
14563                 }
14564             }
14565             return -1;
14566         }else{
14567             return this.items.indexOf(o);
14568         }
14569     },
14570    
14571 /**
14572  * Returns index within the collection of the passed key.
14573  * @param {String} key The key to find the index of.
14574  * @return {Number} index of the key.
14575  */
14576     indexOfKey : function(key){
14577         if(!this.keys.indexOf){
14578             for(var i = 0, len = this.keys.length; i < len; i++){
14579                 if(this.keys[i] == key) {
14580                     return i;
14581                 }
14582             }
14583             return -1;
14584         }else{
14585             return this.keys.indexOf(key);
14586         }
14587     },
14588    
14589 /**
14590  * Returns the item associated with the passed key OR index. Key has priority over index.
14591  * @param {String/Number} key The key or index of the item.
14592  * @return {Object} The item associated with the passed key.
14593  */
14594     item : function(key){
14595         if (key === 'length') {
14596             return null;
14597         }
14598         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
14599         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
14600     },
14601     
14602 /**
14603  * Returns the item at the specified index.
14604  * @param {Number} index The index of the item.
14605  * @return {Object}
14606  */
14607     itemAt : function(index){
14608         return this.items[index];
14609     },
14610     
14611 /**
14612  * Returns the item associated with the passed key.
14613  * @param {String/Number} key The key of the item.
14614  * @return {Object} The item associated with the passed key.
14615  */
14616     key : function(key){
14617         return this.map[key];
14618     },
14619    
14620 /**
14621  * Returns true if the collection contains the passed Object as an item.
14622  * @param {Object} o  The Object to look for in the collection.
14623  * @return {Boolean} True if the collection contains the Object as an item.
14624  */
14625     contains : function(o){
14626         return this.indexOf(o) != -1;
14627     },
14628    
14629 /**
14630  * Returns true if the collection contains the passed Object as a key.
14631  * @param {String} key The key to look for in the collection.
14632  * @return {Boolean} True if the collection contains the Object as a key.
14633  */
14634     containsKey : function(key){
14635         return typeof this.map[key] != "undefined";
14636     },
14637    
14638 /**
14639  * Removes all items from the collection.
14640  */
14641     clear : function(){
14642         this.length = 0;
14643         this.items = [];
14644         this.keys = [];
14645         this.map = {};
14646         this.fireEvent("clear");
14647     },
14648    
14649 /**
14650  * Returns the first item in the collection.
14651  * @return {Object} the first item in the collection..
14652  */
14653     first : function(){
14654         return this.items[0]; 
14655     },
14656    
14657 /**
14658  * Returns the last item in the collection.
14659  * @return {Object} the last item in the collection..
14660  */
14661     last : function(){
14662         return this.items[this.length-1];   
14663     },
14664     
14665     _sort : function(property, dir, fn){
14666         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
14667         fn = fn || function(a, b){
14668             return a-b;
14669         };
14670         var c = [], k = this.keys, items = this.items;
14671         for(var i = 0, len = items.length; i < len; i++){
14672             c[c.length] = {key: k[i], value: items[i], index: i};
14673         }
14674         c.sort(function(a, b){
14675             var v = fn(a[property], b[property]) * dsc;
14676             if(v == 0){
14677                 v = (a.index < b.index ? -1 : 1);
14678             }
14679             return v;
14680         });
14681         for(var i = 0, len = c.length; i < len; i++){
14682             items[i] = c[i].value;
14683             k[i] = c[i].key;
14684         }
14685         this.fireEvent("sort", this);
14686     },
14687     
14688     /**
14689      * Sorts this collection with the passed comparison function
14690      * @param {String} direction (optional) "ASC" or "DESC"
14691      * @param {Function} fn (optional) comparison function
14692      */
14693     sort : function(dir, fn){
14694         this._sort("value", dir, fn);
14695     },
14696     
14697     /**
14698      * Sorts this collection by keys
14699      * @param {String} direction (optional) "ASC" or "DESC"
14700      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
14701      */
14702     keySort : function(dir, fn){
14703         this._sort("key", dir, fn || function(a, b){
14704             return String(a).toUpperCase()-String(b).toUpperCase();
14705         });
14706     },
14707     
14708     /**
14709      * Returns a range of items in this collection
14710      * @param {Number} startIndex (optional) defaults to 0
14711      * @param {Number} endIndex (optional) default to the last item
14712      * @return {Array} An array of items
14713      */
14714     getRange : function(start, end){
14715         var items = this.items;
14716         if(items.length < 1){
14717             return [];
14718         }
14719         start = start || 0;
14720         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
14721         var r = [];
14722         if(start <= end){
14723             for(var i = start; i <= end; i++) {
14724                     r[r.length] = items[i];
14725             }
14726         }else{
14727             for(var i = start; i >= end; i--) {
14728                     r[r.length] = items[i];
14729             }
14730         }
14731         return r;
14732     },
14733         
14734     /**
14735      * Filter the <i>objects</i> in this collection by a specific property. 
14736      * Returns a new collection that has been filtered.
14737      * @param {String} property A property on your objects
14738      * @param {String/RegExp} value Either string that the property values 
14739      * should start with or a RegExp to test against the property
14740      * @return {MixedCollection} The new filtered collection
14741      */
14742     filter : function(property, value){
14743         if(!value.exec){ // not a regex
14744             value = String(value);
14745             if(value.length == 0){
14746                 return this.clone();
14747             }
14748             value = new RegExp("^" + Roo.escapeRe(value), "i");
14749         }
14750         return this.filterBy(function(o){
14751             return o && value.test(o[property]);
14752         });
14753         },
14754     
14755     /**
14756      * Filter by a function. * Returns a new collection that has been filtered.
14757      * The passed function will be called with each 
14758      * object in the collection. If the function returns true, the value is included 
14759      * otherwise it is filtered.
14760      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
14761      * @param {Object} scope (optional) The scope of the function (defaults to this) 
14762      * @return {MixedCollection} The new filtered collection
14763      */
14764     filterBy : function(fn, scope){
14765         var r = new Roo.util.MixedCollection();
14766         r.getKey = this.getKey;
14767         var k = this.keys, it = this.items;
14768         for(var i = 0, len = it.length; i < len; i++){
14769             if(fn.call(scope||this, it[i], k[i])){
14770                                 r.add(k[i], it[i]);
14771                         }
14772         }
14773         return r;
14774     },
14775     
14776     /**
14777      * Creates a duplicate of this collection
14778      * @return {MixedCollection}
14779      */
14780     clone : function(){
14781         var r = new Roo.util.MixedCollection();
14782         var k = this.keys, it = this.items;
14783         for(var i = 0, len = it.length; i < len; i++){
14784             r.add(k[i], it[i]);
14785         }
14786         r.getKey = this.getKey;
14787         return r;
14788     }
14789 });
14790 /**
14791  * Returns the item associated with the passed key or index.
14792  * @method
14793  * @param {String/Number} key The key or index of the item.
14794  * @return {Object} The item associated with the passed key.
14795  */
14796 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
14797  * Based on:
14798  * Ext JS Library 1.1.1
14799  * Copyright(c) 2006-2007, Ext JS, LLC.
14800  *
14801  * Originally Released Under LGPL - original licence link has changed is not relivant.
14802  *
14803  * Fork - LGPL
14804  * <script type="text/javascript">
14805  */
14806 /**
14807  * @class Roo.util.JSON
14808  * Modified version of Douglas Crockford"s json.js that doesn"t
14809  * mess with the Object prototype 
14810  * http://www.json.org/js.html
14811  * @static
14812  */
14813 Roo.util.JSON = new (function(){
14814     var useHasOwn = {}.hasOwnProperty ? true : false;
14815     
14816     // crashes Safari in some instances
14817     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
14818     
14819     var pad = function(n) {
14820         return n < 10 ? "0" + n : n;
14821     };
14822     
14823     var m = {
14824         "\b": '\\b',
14825         "\t": '\\t',
14826         "\n": '\\n',
14827         "\f": '\\f',
14828         "\r": '\\r',
14829         '"' : '\\"',
14830         "\\": '\\\\'
14831     };
14832
14833     var encodeString = function(s){
14834         if (/["\\\x00-\x1f]/.test(s)) {
14835             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
14836                 var c = m[b];
14837                 if(c){
14838                     return c;
14839                 }
14840                 c = b.charCodeAt();
14841                 return "\\u00" +
14842                     Math.floor(c / 16).toString(16) +
14843                     (c % 16).toString(16);
14844             }) + '"';
14845         }
14846         return '"' + s + '"';
14847     };
14848     
14849     var encodeArray = function(o){
14850         var a = ["["], b, i, l = o.length, v;
14851             for (i = 0; i < l; i += 1) {
14852                 v = o[i];
14853                 switch (typeof v) {
14854                     case "undefined":
14855                     case "function":
14856                     case "unknown":
14857                         break;
14858                     default:
14859                         if (b) {
14860                             a.push(',');
14861                         }
14862                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
14863                         b = true;
14864                 }
14865             }
14866             a.push("]");
14867             return a.join("");
14868     };
14869     
14870     var encodeDate = function(o){
14871         return '"' + o.getFullYear() + "-" +
14872                 pad(o.getMonth() + 1) + "-" +
14873                 pad(o.getDate()) + "T" +
14874                 pad(o.getHours()) + ":" +
14875                 pad(o.getMinutes()) + ":" +
14876                 pad(o.getSeconds()) + '"';
14877     };
14878     
14879     /**
14880      * Encodes an Object, Array or other value
14881      * @param {Mixed} o The variable to encode
14882      * @return {String} The JSON string
14883      */
14884     this.encode = function(o)
14885     {
14886         // should this be extended to fully wrap stringify..
14887         
14888         if(typeof o == "undefined" || o === null){
14889             return "null";
14890         }else if(o instanceof Array){
14891             return encodeArray(o);
14892         }else if(o instanceof Date){
14893             return encodeDate(o);
14894         }else if(typeof o == "string"){
14895             return encodeString(o);
14896         }else if(typeof o == "number"){
14897             return isFinite(o) ? String(o) : "null";
14898         }else if(typeof o == "boolean"){
14899             return String(o);
14900         }else {
14901             var a = ["{"], b, i, v;
14902             for (i in o) {
14903                 if(!useHasOwn || o.hasOwnProperty(i)) {
14904                     v = o[i];
14905                     switch (typeof v) {
14906                     case "undefined":
14907                     case "function":
14908                     case "unknown":
14909                         break;
14910                     default:
14911                         if(b){
14912                             a.push(',');
14913                         }
14914                         a.push(this.encode(i), ":",
14915                                 v === null ? "null" : this.encode(v));
14916                         b = true;
14917                     }
14918                 }
14919             }
14920             a.push("}");
14921             return a.join("");
14922         }
14923     };
14924     
14925     /**
14926      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
14927      * @param {String} json The JSON string
14928      * @return {Object} The resulting object
14929      */
14930     this.decode = function(json){
14931         
14932         return  /** eval:var:json */ eval("(" + json + ')');
14933     };
14934 })();
14935 /** 
14936  * Shorthand for {@link Roo.util.JSON#encode}
14937  * @member Roo encode 
14938  * @method */
14939 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
14940 /** 
14941  * Shorthand for {@link Roo.util.JSON#decode}
14942  * @member Roo decode 
14943  * @method */
14944 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
14945 /*
14946  * Based on:
14947  * Ext JS Library 1.1.1
14948  * Copyright(c) 2006-2007, Ext JS, LLC.
14949  *
14950  * Originally Released Under LGPL - original licence link has changed is not relivant.
14951  *
14952  * Fork - LGPL
14953  * <script type="text/javascript">
14954  */
14955  
14956 /**
14957  * @class Roo.util.Format
14958  * Reusable data formatting functions
14959  * @static
14960  */
14961 Roo.util.Format = function(){
14962     var trimRe = /^\s+|\s+$/g;
14963     return {
14964         /**
14965          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
14966          * @param {String} value The string to truncate
14967          * @param {Number} length The maximum length to allow before truncating
14968          * @return {String} The converted text
14969          */
14970         ellipsis : function(value, len){
14971             if(value && value.length > len){
14972                 return value.substr(0, len-3)+"...";
14973             }
14974             return value;
14975         },
14976
14977         /**
14978          * Checks a reference and converts it to empty string if it is undefined
14979          * @param {Mixed} value Reference to check
14980          * @return {Mixed} Empty string if converted, otherwise the original value
14981          */
14982         undef : function(value){
14983             return typeof value != "undefined" ? value : "";
14984         },
14985
14986         /**
14987          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
14988          * @param {String} value The string to encode
14989          * @return {String} The encoded text
14990          */
14991         htmlEncode : function(value){
14992             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
14993         },
14994
14995         /**
14996          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
14997          * @param {String} value The string to decode
14998          * @return {String} The decoded text
14999          */
15000         htmlDecode : function(value){
15001             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
15002         },
15003
15004         /**
15005          * Trims any whitespace from either side of a string
15006          * @param {String} value The text to trim
15007          * @return {String} The trimmed text
15008          */
15009         trim : function(value){
15010             return String(value).replace(trimRe, "");
15011         },
15012
15013         /**
15014          * Returns a substring from within an original string
15015          * @param {String} value The original text
15016          * @param {Number} start The start index of the substring
15017          * @param {Number} length The length of the substring
15018          * @return {String} The substring
15019          */
15020         substr : function(value, start, length){
15021             return String(value).substr(start, length);
15022         },
15023
15024         /**
15025          * Converts a string to all lower case letters
15026          * @param {String} value The text to convert
15027          * @return {String} The converted text
15028          */
15029         lowercase : function(value){
15030             return String(value).toLowerCase();
15031         },
15032
15033         /**
15034          * Converts a string to all upper case letters
15035          * @param {String} value The text to convert
15036          * @return {String} The converted text
15037          */
15038         uppercase : function(value){
15039             return String(value).toUpperCase();
15040         },
15041
15042         /**
15043          * Converts the first character only of a string to upper case
15044          * @param {String} value The text to convert
15045          * @return {String} The converted text
15046          */
15047         capitalize : function(value){
15048             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
15049         },
15050
15051         // private
15052         call : function(value, fn){
15053             if(arguments.length > 2){
15054                 var args = Array.prototype.slice.call(arguments, 2);
15055                 args.unshift(value);
15056                  
15057                 return /** eval:var:value */  eval(fn).apply(window, args);
15058             }else{
15059                 /** eval:var:value */
15060                 return /** eval:var:value */ eval(fn).call(window, value);
15061             }
15062         },
15063
15064        
15065         /**
15066          * safer version of Math.toFixed..??/
15067          * @param {Number/String} value The numeric value to format
15068          * @param {Number/String} value Decimal places 
15069          * @return {String} The formatted currency string
15070          */
15071         toFixed : function(v, n)
15072         {
15073             // why not use to fixed - precision is buggered???
15074             if (!n) {
15075                 return Math.round(v-0);
15076             }
15077             var fact = Math.pow(10,n+1);
15078             v = (Math.round((v-0)*fact))/fact;
15079             var z = (''+fact).substring(2);
15080             if (v == Math.floor(v)) {
15081                 return Math.floor(v) + '.' + z;
15082             }
15083             
15084             // now just padd decimals..
15085             var ps = String(v).split('.');
15086             var fd = (ps[1] + z);
15087             var r = fd.substring(0,n); 
15088             var rm = fd.substring(n); 
15089             if (rm < 5) {
15090                 return ps[0] + '.' + r;
15091             }
15092             r*=1; // turn it into a number;
15093             r++;
15094             if (String(r).length != n) {
15095                 ps[0]*=1;
15096                 ps[0]++;
15097                 r = String(r).substring(1); // chop the end off.
15098             }
15099             
15100             return ps[0] + '.' + r;
15101              
15102         },
15103         
15104         /**
15105          * Format a number as US currency
15106          * @param {Number/String} value The numeric value to format
15107          * @return {String} The formatted currency string
15108          */
15109         usMoney : function(v){
15110             return '$' + Roo.util.Format.number(v);
15111         },
15112         
15113         /**
15114          * Format a number
15115          * eventually this should probably emulate php's number_format
15116          * @param {Number/String} value The numeric value to format
15117          * @param {Number} decimals number of decimal places
15118          * @param {String} delimiter for thousands (default comma)
15119          * @return {String} The formatted currency string
15120          */
15121         number : function(v, decimals, thousandsDelimiter)
15122         {
15123             // multiply and round.
15124             decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
15125             thousandsDelimiter = typeof(thousandsDelimiter) == 'undefined' ? ',' : thousandsDelimiter;
15126             
15127             var mul = Math.pow(10, decimals);
15128             var zero = String(mul).substring(1);
15129             v = (Math.round((v-0)*mul))/mul;
15130             
15131             // if it's '0' number.. then
15132             
15133             //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
15134             v = String(v);
15135             var ps = v.split('.');
15136             var whole = ps[0];
15137             
15138             var r = /(\d+)(\d{3})/;
15139             // add comma's
15140             
15141             if(thousandsDelimiter.length != 0) {
15142                 whole = whole.replace(/\B(?=(\d{3})+(?!\d))/g, thousandsDelimiter );
15143             } 
15144             
15145             var sub = ps[1] ?
15146                     // has decimals..
15147                     (decimals ?  ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
15148                     // does not have decimals
15149                     (decimals ? ('.' + zero) : '');
15150             
15151             
15152             return whole + sub ;
15153         },
15154         
15155         /**
15156          * Parse a value into a formatted date using the specified format pattern.
15157          * @param {Mixed} value The value to format
15158          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
15159          * @return {String} The formatted date string
15160          */
15161         date : function(v, format){
15162             if(!v){
15163                 return "";
15164             }
15165             if(!(v instanceof Date)){
15166                 v = new Date(Date.parse(v));
15167             }
15168             return v.dateFormat(format || Roo.util.Format.defaults.date);
15169         },
15170
15171         /**
15172          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
15173          * @param {String} format Any valid date format string
15174          * @return {Function} The date formatting function
15175          */
15176         dateRenderer : function(format){
15177             return function(v){
15178                 return Roo.util.Format.date(v, format);  
15179             };
15180         },
15181
15182         // private
15183         stripTagsRE : /<\/?[^>]+>/gi,
15184         
15185         /**
15186          * Strips all HTML tags
15187          * @param {Mixed} value The text from which to strip tags
15188          * @return {String} The stripped text
15189          */
15190         stripTags : function(v){
15191             return !v ? v : String(v).replace(this.stripTagsRE, "");
15192         },
15193         
15194         /**
15195          * Size in Mb,Gb etc.
15196          * @param {Number} value The number to be formated
15197          * @param {number} decimals how many decimal places
15198          * @return {String} the formated string
15199          */
15200         size : function(value, decimals)
15201         {
15202             var sizes = ['b', 'k', 'M', 'G', 'T'];
15203             if (value == 0) {
15204                 return 0;
15205             }
15206             var i = parseInt(Math.floor(Math.log(value) / Math.log(1024)));
15207             return Roo.util.Format.number(value/ Math.pow(1024, i) ,decimals)   + sizes[i];
15208         }
15209         
15210         
15211         
15212     };
15213 }();
15214 Roo.util.Format.defaults = {
15215     date : 'd/M/Y'
15216 };/*
15217  * Based on:
15218  * Ext JS Library 1.1.1
15219  * Copyright(c) 2006-2007, Ext JS, LLC.
15220  *
15221  * Originally Released Under LGPL - original licence link has changed is not relivant.
15222  *
15223  * Fork - LGPL
15224  * <script type="text/javascript">
15225  */
15226
15227
15228  
15229
15230 /**
15231  * @class Roo.MasterTemplate
15232  * @extends Roo.Template
15233  * Provides a template that can have child templates. The syntax is:
15234 <pre><code>
15235 var t = new Roo.MasterTemplate(
15236         '&lt;select name="{name}"&gt;',
15237                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
15238         '&lt;/select&gt;'
15239 );
15240 t.add('options', {value: 'foo', text: 'bar'});
15241 // or you can add multiple child elements in one shot
15242 t.addAll('options', [
15243     {value: 'foo', text: 'bar'},
15244     {value: 'foo2', text: 'bar2'},
15245     {value: 'foo3', text: 'bar3'}
15246 ]);
15247 // then append, applying the master template values
15248 t.append('my-form', {name: 'my-select'});
15249 </code></pre>
15250 * A name attribute for the child template is not required if you have only one child
15251 * template or you want to refer to them by index.
15252  */
15253 Roo.MasterTemplate = function(){
15254     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
15255     this.originalHtml = this.html;
15256     var st = {};
15257     var m, re = this.subTemplateRe;
15258     re.lastIndex = 0;
15259     var subIndex = 0;
15260     while(m = re.exec(this.html)){
15261         var name = m[1], content = m[2];
15262         st[subIndex] = {
15263             name: name,
15264             index: subIndex,
15265             buffer: [],
15266             tpl : new Roo.Template(content)
15267         };
15268         if(name){
15269             st[name] = st[subIndex];
15270         }
15271         st[subIndex].tpl.compile();
15272         st[subIndex].tpl.call = this.call.createDelegate(this);
15273         subIndex++;
15274     }
15275     this.subCount = subIndex;
15276     this.subs = st;
15277 };
15278 Roo.extend(Roo.MasterTemplate, Roo.Template, {
15279     /**
15280     * The regular expression used to match sub templates
15281     * @type RegExp
15282     * @property
15283     */
15284     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
15285
15286     /**
15287      * Applies the passed values to a child template.
15288      * @param {String/Number} name (optional) The name or index of the child template
15289      * @param {Array/Object} values The values to be applied to the template
15290      * @return {MasterTemplate} this
15291      */
15292      add : function(name, values){
15293         if(arguments.length == 1){
15294             values = arguments[0];
15295             name = 0;
15296         }
15297         var s = this.subs[name];
15298         s.buffer[s.buffer.length] = s.tpl.apply(values);
15299         return this;
15300     },
15301
15302     /**
15303      * Applies all the passed values to a child template.
15304      * @param {String/Number} name (optional) The name or index of the child template
15305      * @param {Array} values The values to be applied to the template, this should be an array of objects.
15306      * @param {Boolean} reset (optional) True to reset the template first
15307      * @return {MasterTemplate} this
15308      */
15309     fill : function(name, values, reset){
15310         var a = arguments;
15311         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
15312             values = a[0];
15313             name = 0;
15314             reset = a[1];
15315         }
15316         if(reset){
15317             this.reset();
15318         }
15319         for(var i = 0, len = values.length; i < len; i++){
15320             this.add(name, values[i]);
15321         }
15322         return this;
15323     },
15324
15325     /**
15326      * Resets the template for reuse
15327      * @return {MasterTemplate} this
15328      */
15329      reset : function(){
15330         var s = this.subs;
15331         for(var i = 0; i < this.subCount; i++){
15332             s[i].buffer = [];
15333         }
15334         return this;
15335     },
15336
15337     applyTemplate : function(values){
15338         var s = this.subs;
15339         var replaceIndex = -1;
15340         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
15341             return s[++replaceIndex].buffer.join("");
15342         });
15343         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
15344     },
15345
15346     apply : function(){
15347         return this.applyTemplate.apply(this, arguments);
15348     },
15349
15350     compile : function(){return this;}
15351 });
15352
15353 /**
15354  * Alias for fill().
15355  * @method
15356  */
15357 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
15358  /**
15359  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
15360  * var tpl = Roo.MasterTemplate.from('element-id');
15361  * @param {String/HTMLElement} el
15362  * @param {Object} config
15363  * @static
15364  */
15365 Roo.MasterTemplate.from = function(el, config){
15366     el = Roo.getDom(el);
15367     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
15368 };/*
15369  * Based on:
15370  * Ext JS Library 1.1.1
15371  * Copyright(c) 2006-2007, Ext JS, LLC.
15372  *
15373  * Originally Released Under LGPL - original licence link has changed is not relivant.
15374  *
15375  * Fork - LGPL
15376  * <script type="text/javascript">
15377  */
15378
15379  
15380 /**
15381  * @class Roo.util.CSS
15382  * Utility class for manipulating CSS rules
15383  * @static
15384
15385  */
15386 Roo.util.CSS = function(){
15387         var rules = null;
15388         var doc = document;
15389
15390     var camelRe = /(-[a-z])/gi;
15391     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
15392
15393    return {
15394    /**
15395     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
15396     * tag and appended to the HEAD of the document.
15397     * @param {String|Object} cssText The text containing the css rules
15398     * @param {String} id An id to add to the stylesheet for later removal
15399     * @return {StyleSheet}
15400     */
15401     createStyleSheet : function(cssText, id){
15402         var ss;
15403         var head = doc.getElementsByTagName("head")[0];
15404         var nrules = doc.createElement("style");
15405         nrules.setAttribute("type", "text/css");
15406         if(id){
15407             nrules.setAttribute("id", id);
15408         }
15409         if (typeof(cssText) != 'string') {
15410             // support object maps..
15411             // not sure if this a good idea.. 
15412             // perhaps it should be merged with the general css handling
15413             // and handle js style props.
15414             var cssTextNew = [];
15415             for(var n in cssText) {
15416                 var citems = [];
15417                 for(var k in cssText[n]) {
15418                     citems.push( k + ' : ' +cssText[n][k] + ';' );
15419                 }
15420                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
15421                 
15422             }
15423             cssText = cssTextNew.join("\n");
15424             
15425         }
15426        
15427        
15428        if(Roo.isIE){
15429            head.appendChild(nrules);
15430            ss = nrules.styleSheet;
15431            ss.cssText = cssText;
15432        }else{
15433            try{
15434                 nrules.appendChild(doc.createTextNode(cssText));
15435            }catch(e){
15436                nrules.cssText = cssText; 
15437            }
15438            head.appendChild(nrules);
15439            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
15440        }
15441        this.cacheStyleSheet(ss);
15442        return ss;
15443    },
15444
15445    /**
15446     * Removes a style or link tag by id
15447     * @param {String} id The id of the tag
15448     */
15449    removeStyleSheet : function(id){
15450        var existing = doc.getElementById(id);
15451        if(existing){
15452            existing.parentNode.removeChild(existing);
15453        }
15454    },
15455
15456    /**
15457     * Dynamically swaps an existing stylesheet reference for a new one
15458     * @param {String} id The id of an existing link tag to remove
15459     * @param {String} url The href of the new stylesheet to include
15460     */
15461    swapStyleSheet : function(id, url){
15462        this.removeStyleSheet(id);
15463        var ss = doc.createElement("link");
15464        ss.setAttribute("rel", "stylesheet");
15465        ss.setAttribute("type", "text/css");
15466        ss.setAttribute("id", id);
15467        ss.setAttribute("href", url);
15468        doc.getElementsByTagName("head")[0].appendChild(ss);
15469    },
15470    
15471    /**
15472     * Refresh the rule cache if you have dynamically added stylesheets
15473     * @return {Object} An object (hash) of rules indexed by selector
15474     */
15475    refreshCache : function(){
15476        return this.getRules(true);
15477    },
15478
15479    // private
15480    cacheStyleSheet : function(stylesheet){
15481        if(!rules){
15482            rules = {};
15483        }
15484        try{// try catch for cross domain access issue
15485            var ssRules = stylesheet.cssRules || stylesheet.rules;
15486            for(var j = ssRules.length-1; j >= 0; --j){
15487                rules[ssRules[j].selectorText] = ssRules[j];
15488            }
15489        }catch(e){}
15490    },
15491    
15492    /**
15493     * Gets all css rules for the document
15494     * @param {Boolean} refreshCache true to refresh the internal cache
15495     * @return {Object} An object (hash) of rules indexed by selector
15496     */
15497    getRules : function(refreshCache){
15498                 if(rules == null || refreshCache){
15499                         rules = {};
15500                         var ds = doc.styleSheets;
15501                         for(var i =0, len = ds.length; i < len; i++){
15502                             try{
15503                         this.cacheStyleSheet(ds[i]);
15504                     }catch(e){} 
15505                 }
15506                 }
15507                 return rules;
15508         },
15509         
15510         /**
15511     * Gets an an individual CSS rule by selector(s)
15512     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
15513     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
15514     * @return {CSSRule} The CSS rule or null if one is not found
15515     */
15516    getRule : function(selector, refreshCache){
15517                 var rs = this.getRules(refreshCache);
15518                 if(!(selector instanceof Array)){
15519                     return rs[selector];
15520                 }
15521                 for(var i = 0; i < selector.length; i++){
15522                         if(rs[selector[i]]){
15523                                 return rs[selector[i]];
15524                         }
15525                 }
15526                 return null;
15527         },
15528         
15529         
15530         /**
15531     * Updates a rule property
15532     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
15533     * @param {String} property The css property
15534     * @param {String} value The new value for the property
15535     * @return {Boolean} true If a rule was found and updated
15536     */
15537    updateRule : function(selector, property, value){
15538                 if(!(selector instanceof Array)){
15539                         var rule = this.getRule(selector);
15540                         if(rule){
15541                                 rule.style[property.replace(camelRe, camelFn)] = value;
15542                                 return true;
15543                         }
15544                 }else{
15545                         for(var i = 0; i < selector.length; i++){
15546                                 if(this.updateRule(selector[i], property, value)){
15547                                         return true;
15548                                 }
15549                         }
15550                 }
15551                 return false;
15552         }
15553    };   
15554 }();/*
15555  * Based on:
15556  * Ext JS Library 1.1.1
15557  * Copyright(c) 2006-2007, Ext JS, LLC.
15558  *
15559  * Originally Released Under LGPL - original licence link has changed is not relivant.
15560  *
15561  * Fork - LGPL
15562  * <script type="text/javascript">
15563  */
15564
15565  
15566
15567 /**
15568  * @class Roo.util.ClickRepeater
15569  * @extends Roo.util.Observable
15570  * 
15571  * A wrapper class which can be applied to any element. Fires a "click" event while the
15572  * mouse is pressed. The interval between firings may be specified in the config but
15573  * defaults to 10 milliseconds.
15574  * 
15575  * Optionally, a CSS class may be applied to the element during the time it is pressed.
15576  * 
15577  * @cfg {String/HTMLElement/Element} el The element to act as a button.
15578  * @cfg {Number} delay The initial delay before the repeating event begins firing.
15579  * Similar to an autorepeat key delay.
15580  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
15581  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
15582  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
15583  *           "interval" and "delay" are ignored. "immediate" is honored.
15584  * @cfg {Boolean} preventDefault True to prevent the default click event
15585  * @cfg {Boolean} stopDefault True to stop the default click event
15586  * 
15587  * @history
15588  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
15589  *     2007-02-02 jvs Renamed to ClickRepeater
15590  *   2007-02-03 jvs Modifications for FF Mac and Safari 
15591  *
15592  *  @constructor
15593  * @param {String/HTMLElement/Element} el The element to listen on
15594  * @param {Object} config
15595  **/
15596 Roo.util.ClickRepeater = function(el, config)
15597 {
15598     this.el = Roo.get(el);
15599     this.el.unselectable();
15600
15601     Roo.apply(this, config);
15602
15603     this.addEvents({
15604     /**
15605      * @event mousedown
15606      * Fires when the mouse button is depressed.
15607      * @param {Roo.util.ClickRepeater} this
15608      */
15609         "mousedown" : true,
15610     /**
15611      * @event click
15612      * Fires on a specified interval during the time the element is pressed.
15613      * @param {Roo.util.ClickRepeater} this
15614      */
15615         "click" : true,
15616     /**
15617      * @event mouseup
15618      * Fires when the mouse key is released.
15619      * @param {Roo.util.ClickRepeater} this
15620      */
15621         "mouseup" : true
15622     });
15623
15624     this.el.on("mousedown", this.handleMouseDown, this);
15625     if(this.preventDefault || this.stopDefault){
15626         this.el.on("click", function(e){
15627             if(this.preventDefault){
15628                 e.preventDefault();
15629             }
15630             if(this.stopDefault){
15631                 e.stopEvent();
15632             }
15633         }, this);
15634     }
15635
15636     // allow inline handler
15637     if(this.handler){
15638         this.on("click", this.handler,  this.scope || this);
15639     }
15640
15641     Roo.util.ClickRepeater.superclass.constructor.call(this);
15642 };
15643
15644 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
15645     interval : 20,
15646     delay: 250,
15647     preventDefault : true,
15648     stopDefault : false,
15649     timer : 0,
15650
15651     // private
15652     handleMouseDown : function(){
15653         clearTimeout(this.timer);
15654         this.el.blur();
15655         if(this.pressClass){
15656             this.el.addClass(this.pressClass);
15657         }
15658         this.mousedownTime = new Date();
15659
15660         Roo.get(document).on("mouseup", this.handleMouseUp, this);
15661         this.el.on("mouseout", this.handleMouseOut, this);
15662
15663         this.fireEvent("mousedown", this);
15664         this.fireEvent("click", this);
15665         
15666         this.timer = this.click.defer(this.delay || this.interval, this);
15667     },
15668
15669     // private
15670     click : function(){
15671         this.fireEvent("click", this);
15672         this.timer = this.click.defer(this.getInterval(), this);
15673     },
15674
15675     // private
15676     getInterval: function(){
15677         if(!this.accelerate){
15678             return this.interval;
15679         }
15680         var pressTime = this.mousedownTime.getElapsed();
15681         if(pressTime < 500){
15682             return 400;
15683         }else if(pressTime < 1700){
15684             return 320;
15685         }else if(pressTime < 2600){
15686             return 250;
15687         }else if(pressTime < 3500){
15688             return 180;
15689         }else if(pressTime < 4400){
15690             return 140;
15691         }else if(pressTime < 5300){
15692             return 80;
15693         }else if(pressTime < 6200){
15694             return 50;
15695         }else{
15696             return 10;
15697         }
15698     },
15699
15700     // private
15701     handleMouseOut : function(){
15702         clearTimeout(this.timer);
15703         if(this.pressClass){
15704             this.el.removeClass(this.pressClass);
15705         }
15706         this.el.on("mouseover", this.handleMouseReturn, this);
15707     },
15708
15709     // private
15710     handleMouseReturn : function(){
15711         this.el.un("mouseover", this.handleMouseReturn);
15712         if(this.pressClass){
15713             this.el.addClass(this.pressClass);
15714         }
15715         this.click();
15716     },
15717
15718     // private
15719     handleMouseUp : function(){
15720         clearTimeout(this.timer);
15721         this.el.un("mouseover", this.handleMouseReturn);
15722         this.el.un("mouseout", this.handleMouseOut);
15723         Roo.get(document).un("mouseup", this.handleMouseUp);
15724         this.el.removeClass(this.pressClass);
15725         this.fireEvent("mouseup", this);
15726     }
15727 });/**
15728  * @class Roo.util.Clipboard
15729  * @static
15730  * 
15731  * Clipboard UTILS
15732  * 
15733  **/
15734 Roo.util.Clipboard = {
15735     /**
15736      * Writes a string to the clipboard - using the Clipboard API if https, otherwise using text area.
15737      * @param {String} text to copy to clipboard
15738      */
15739     write : function(text) {
15740         // navigator clipboard api needs a secure context (https)
15741         if (navigator.clipboard && window.isSecureContext) {
15742             // navigator clipboard api method'
15743             navigator.clipboard.writeText(text);
15744             return ;
15745         } 
15746         // text area method
15747         var ta = document.createElement("textarea");
15748         ta.value = text;
15749         // make the textarea out of viewport
15750         ta.style.position = "fixed";
15751         ta.style.left = "-999999px";
15752         ta.style.top = "-999999px";
15753         document.body.appendChild(ta);
15754         ta.focus();
15755         ta.select();
15756         document.execCommand('copy');
15757         (function() {
15758             ta.remove();
15759         }).defer(100);
15760         
15761     }
15762         
15763 }
15764     /*
15765  * Based on:
15766  * Ext JS Library 1.1.1
15767  * Copyright(c) 2006-2007, Ext JS, LLC.
15768  *
15769  * Originally Released Under LGPL - original licence link has changed is not relivant.
15770  *
15771  * Fork - LGPL
15772  * <script type="text/javascript">
15773  */
15774
15775  
15776 /**
15777  * @class Roo.KeyNav
15778  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
15779  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
15780  * way to implement custom navigation schemes for any UI component.</p>
15781  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
15782  * pageUp, pageDown, del, home, end.  Usage:</p>
15783  <pre><code>
15784 var nav = new Roo.KeyNav("my-element", {
15785     "left" : function(e){
15786         this.moveLeft(e.ctrlKey);
15787     },
15788     "right" : function(e){
15789         this.moveRight(e.ctrlKey);
15790     },
15791     "enter" : function(e){
15792         this.save();
15793     },
15794     scope : this
15795 });
15796 </code></pre>
15797  * @constructor
15798  * @param {String/HTMLElement/Roo.Element} el The element to bind to
15799  * @param {Object} config The config
15800  */
15801 Roo.KeyNav = function(el, config){
15802     this.el = Roo.get(el);
15803     Roo.apply(this, config);
15804     if(!this.disabled){
15805         this.disabled = true;
15806         this.enable();
15807     }
15808 };
15809
15810 Roo.KeyNav.prototype = {
15811     /**
15812      * @cfg {Boolean} disabled
15813      * True to disable this KeyNav instance (defaults to false)
15814      */
15815     disabled : false,
15816     /**
15817      * @cfg {String} defaultEventAction
15818      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
15819      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
15820      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
15821      */
15822     defaultEventAction: "stopEvent",
15823     /**
15824      * @cfg {Boolean} forceKeyDown
15825      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
15826      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
15827      * handle keydown instead of keypress.
15828      */
15829     forceKeyDown : false,
15830
15831     // private
15832     prepareEvent : function(e){
15833         var k = e.getKey();
15834         var h = this.keyToHandler[k];
15835         //if(h && this[h]){
15836         //    e.stopPropagation();
15837         //}
15838         if(Roo.isSafari && h && k >= 37 && k <= 40){
15839             e.stopEvent();
15840         }
15841     },
15842
15843     // private
15844     relay : function(e){
15845         var k = e.getKey();
15846         var h = this.keyToHandler[k];
15847         if(h && this[h]){
15848             if(this.doRelay(e, this[h], h) !== true){
15849                 e[this.defaultEventAction]();
15850             }
15851         }
15852     },
15853
15854     // private
15855     doRelay : function(e, h, hname){
15856         return h.call(this.scope || this, e);
15857     },
15858
15859     // possible handlers
15860     enter : false,
15861     left : false,
15862     right : false,
15863     up : false,
15864     down : false,
15865     tab : false,
15866     esc : false,
15867     pageUp : false,
15868     pageDown : false,
15869     del : false,
15870     home : false,
15871     end : false,
15872
15873     // quick lookup hash
15874     keyToHandler : {
15875         37 : "left",
15876         39 : "right",
15877         38 : "up",
15878         40 : "down",
15879         33 : "pageUp",
15880         34 : "pageDown",
15881         46 : "del",
15882         36 : "home",
15883         35 : "end",
15884         13 : "enter",
15885         27 : "esc",
15886         9  : "tab"
15887     },
15888
15889         /**
15890          * Enable this KeyNav
15891          */
15892         enable: function(){
15893                 if(this.disabled){
15894             // ie won't do special keys on keypress, no one else will repeat keys with keydown
15895             // the EventObject will normalize Safari automatically
15896             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
15897                 this.el.on("keydown", this.relay,  this);
15898             }else{
15899                 this.el.on("keydown", this.prepareEvent,  this);
15900                 this.el.on("keypress", this.relay,  this);
15901             }
15902                     this.disabled = false;
15903                 }
15904         },
15905
15906         /**
15907          * Disable this KeyNav
15908          */
15909         disable: function(){
15910                 if(!this.disabled){
15911                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
15912                 this.el.un("keydown", this.relay);
15913             }else{
15914                 this.el.un("keydown", this.prepareEvent);
15915                 this.el.un("keypress", this.relay);
15916             }
15917                     this.disabled = true;
15918                 }
15919         }
15920 };/*
15921  * Based on:
15922  * Ext JS Library 1.1.1
15923  * Copyright(c) 2006-2007, Ext JS, LLC.
15924  *
15925  * Originally Released Under LGPL - original licence link has changed is not relivant.
15926  *
15927  * Fork - LGPL
15928  * <script type="text/javascript">
15929  */
15930
15931  
15932 /**
15933  * @class Roo.KeyMap
15934  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
15935  * The constructor accepts the same config object as defined by {@link #addBinding}.
15936  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
15937  * combination it will call the function with this signature (if the match is a multi-key
15938  * combination the callback will still be called only once): (String key, Roo.EventObject e)
15939  * A KeyMap can also handle a string representation of keys.<br />
15940  * Usage:
15941  <pre><code>
15942 // map one key by key code
15943 var map = new Roo.KeyMap("my-element", {
15944     key: 13, // or Roo.EventObject.ENTER
15945     fn: myHandler,
15946     scope: myObject
15947 });
15948
15949 // map multiple keys to one action by string
15950 var map = new Roo.KeyMap("my-element", {
15951     key: "a\r\n\t",
15952     fn: myHandler,
15953     scope: myObject
15954 });
15955
15956 // map multiple keys to multiple actions by strings and array of codes
15957 var map = new Roo.KeyMap("my-element", [
15958     {
15959         key: [10,13],
15960         fn: function(){ alert("Return was pressed"); }
15961     }, {
15962         key: "abc",
15963         fn: function(){ alert('a, b or c was pressed'); }
15964     }, {
15965         key: "\t",
15966         ctrl:true,
15967         shift:true,
15968         fn: function(){ alert('Control + shift + tab was pressed.'); }
15969     }
15970 ]);
15971 </code></pre>
15972  * <b>Note: A KeyMap starts enabled</b>
15973  * @constructor
15974  * @param {String/HTMLElement/Roo.Element} el The element to bind to
15975  * @param {Object} config The config (see {@link #addBinding})
15976  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
15977  */
15978 Roo.KeyMap = function(el, config, eventName){
15979     this.el  = Roo.get(el);
15980     this.eventName = eventName || "keydown";
15981     this.bindings = [];
15982     if(config){
15983         this.addBinding(config);
15984     }
15985     this.enable();
15986 };
15987
15988 Roo.KeyMap.prototype = {
15989     /**
15990      * True to stop the event from bubbling and prevent the default browser action if the
15991      * key was handled by the KeyMap (defaults to false)
15992      * @type Boolean
15993      */
15994     stopEvent : false,
15995
15996     /**
15997      * Add a new binding to this KeyMap. The following config object properties are supported:
15998      * <pre>
15999 Property    Type             Description
16000 ----------  ---------------  ----------------------------------------------------------------------
16001 key         String/Array     A single keycode or an array of keycodes to handle
16002 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
16003 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
16004 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
16005 fn          Function         The function to call when KeyMap finds the expected key combination
16006 scope       Object           The scope of the callback function
16007 </pre>
16008      *
16009      * Usage:
16010      * <pre><code>
16011 // Create a KeyMap
16012 var map = new Roo.KeyMap(document, {
16013     key: Roo.EventObject.ENTER,
16014     fn: handleKey,
16015     scope: this
16016 });
16017
16018 //Add a new binding to the existing KeyMap later
16019 map.addBinding({
16020     key: 'abc',
16021     shift: true,
16022     fn: handleKey,
16023     scope: this
16024 });
16025 </code></pre>
16026      * @param {Object/Array} config A single KeyMap config or an array of configs
16027      */
16028         addBinding : function(config){
16029         if(config instanceof Array){
16030             for(var i = 0, len = config.length; i < len; i++){
16031                 this.addBinding(config[i]);
16032             }
16033             return;
16034         }
16035         var keyCode = config.key,
16036             shift = config.shift, 
16037             ctrl = config.ctrl, 
16038             alt = config.alt,
16039             fn = config.fn,
16040             scope = config.scope;
16041         if(typeof keyCode == "string"){
16042             var ks = [];
16043             var keyString = keyCode.toUpperCase();
16044             for(var j = 0, len = keyString.length; j < len; j++){
16045                 ks.push(keyString.charCodeAt(j));
16046             }
16047             keyCode = ks;
16048         }
16049         var keyArray = keyCode instanceof Array;
16050         var handler = function(e){
16051             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
16052                 var k = e.getKey();
16053                 if(keyArray){
16054                     for(var i = 0, len = keyCode.length; i < len; i++){
16055                         if(keyCode[i] == k){
16056                           if(this.stopEvent){
16057                               e.stopEvent();
16058                           }
16059                           fn.call(scope || window, k, e);
16060                           return;
16061                         }
16062                     }
16063                 }else{
16064                     if(k == keyCode){
16065                         if(this.stopEvent){
16066                            e.stopEvent();
16067                         }
16068                         fn.call(scope || window, k, e);
16069                     }
16070                 }
16071             }
16072         };
16073         this.bindings.push(handler);  
16074         },
16075
16076     /**
16077      * Shorthand for adding a single key listener
16078      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
16079      * following options:
16080      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
16081      * @param {Function} fn The function to call
16082      * @param {Object} scope (optional) The scope of the function
16083      */
16084     on : function(key, fn, scope){
16085         var keyCode, shift, ctrl, alt;
16086         if(typeof key == "object" && !(key instanceof Array)){
16087             keyCode = key.key;
16088             shift = key.shift;
16089             ctrl = key.ctrl;
16090             alt = key.alt;
16091         }else{
16092             keyCode = key;
16093         }
16094         this.addBinding({
16095             key: keyCode,
16096             shift: shift,
16097             ctrl: ctrl,
16098             alt: alt,
16099             fn: fn,
16100             scope: scope
16101         })
16102     },
16103
16104     // private
16105     handleKeyDown : function(e){
16106             if(this.enabled){ //just in case
16107             var b = this.bindings;
16108             for(var i = 0, len = b.length; i < len; i++){
16109                 b[i].call(this, e);
16110             }
16111             }
16112         },
16113         
16114         /**
16115          * Returns true if this KeyMap is enabled
16116          * @return {Boolean} 
16117          */
16118         isEnabled : function(){
16119             return this.enabled;  
16120         },
16121         
16122         /**
16123          * Enables this KeyMap
16124          */
16125         enable: function(){
16126                 if(!this.enabled){
16127                     this.el.on(this.eventName, this.handleKeyDown, this);
16128                     this.enabled = true;
16129                 }
16130         },
16131
16132         /**
16133          * Disable this KeyMap
16134          */
16135         disable: function(){
16136                 if(this.enabled){
16137                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
16138                     this.enabled = false;
16139                 }
16140         }
16141 };/*
16142  * Based on:
16143  * Ext JS Library 1.1.1
16144  * Copyright(c) 2006-2007, Ext JS, LLC.
16145  *
16146  * Originally Released Under LGPL - original licence link has changed is not relivant.
16147  *
16148  * Fork - LGPL
16149  * <script type="text/javascript">
16150  */
16151
16152  
16153 /**
16154  * @class Roo.util.TextMetrics
16155  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
16156  * wide, in pixels, a given block of text will be.
16157  * @static
16158  */
16159 Roo.util.TextMetrics = function(){
16160     var shared;
16161     return {
16162         /**
16163          * Measures the size of the specified text
16164          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
16165          * that can affect the size of the rendered text
16166          * @param {String} text The text to measure
16167          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
16168          * in order to accurately measure the text height
16169          * @return {Object} An object containing the text's size {width: (width), height: (height)}
16170          */
16171         measure : function(el, text, fixedWidth){
16172             if(!shared){
16173                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
16174             }
16175             shared.bind(el);
16176             shared.setFixedWidth(fixedWidth || 'auto');
16177             return shared.getSize(text);
16178         },
16179
16180         /**
16181          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
16182          * the overhead of multiple calls to initialize the style properties on each measurement.
16183          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
16184          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
16185          * in order to accurately measure the text height
16186          * @return {Roo.util.TextMetrics.Instance} instance The new instance
16187          */
16188         createInstance : function(el, fixedWidth){
16189             return Roo.util.TextMetrics.Instance(el, fixedWidth);
16190         }
16191     };
16192 }();
16193
16194 /**
16195  * @class Roo.util.TextMetrics.Instance
16196  * Instance of  TextMetrics Calcuation
16197  * @constructor
16198  * Create a new TextMetrics Instance
16199  * @param {Object} bindto
16200  * @param {Boolean} fixedWidth
16201  */
16202
16203 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth)
16204 {
16205     var ml = new Roo.Element(document.createElement('div'));
16206     document.body.appendChild(ml.dom);
16207     ml.position('absolute');
16208     ml.setLeftTop(-1000, -1000);
16209     ml.hide();
16210
16211     if(fixedWidth){
16212         ml.setWidth(fixedWidth);
16213     }
16214      
16215     var instance = {
16216         /**
16217          * Returns the size of the specified text based on the internal element's style and width properties
16218          * @param {String} text The text to measure
16219          * @return {Object} An object containing the text's size {width: (width), height: (height)}
16220          */
16221         getSize : function(text){
16222             ml.update(text);
16223             var s = ml.getSize();
16224             ml.update('');
16225             return s;
16226         },
16227
16228         /**
16229          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
16230          * that can affect the size of the rendered text
16231          * @param {String/HTMLElement} el The element, dom node or id
16232          */
16233         bind : function(el){
16234             ml.setStyle(
16235                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
16236             );
16237         },
16238
16239         /**
16240          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
16241          * to set a fixed width in order to accurately measure the text height.
16242          * @param {Number} width The width to set on the element
16243          */
16244         setFixedWidth : function(width){
16245             ml.setWidth(width);
16246         },
16247
16248         /**
16249          * Returns the measured width of the specified text
16250          * @param {String} text The text to measure
16251          * @return {Number} width The width in pixels
16252          */
16253         getWidth : function(text){
16254             ml.dom.style.width = 'auto';
16255             return this.getSize(text).width;
16256         },
16257
16258         /**
16259          * Returns the measured height of the specified text.  For multiline text, be sure to call
16260          * {@link #setFixedWidth} if necessary.
16261          * @param {String} text The text to measure
16262          * @return {Number} height The height in pixels
16263          */
16264         getHeight : function(text){
16265             return this.getSize(text).height;
16266         }
16267     };
16268
16269     instance.bind(bindTo);
16270
16271     return instance;
16272 };
16273
16274 // backwards compat
16275 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
16276  * Based on:
16277  * Ext JS Library 1.1.1
16278  * Copyright(c) 2006-2007, Ext JS, LLC.
16279  *
16280  * Originally Released Under LGPL - original licence link has changed is not relivant.
16281  *
16282  * Fork - LGPL
16283  * <script type="text/javascript">
16284  */
16285
16286 /**
16287  * @class Roo.state.Provider
16288  * Abstract base class for state provider implementations. This class provides methods
16289  * for encoding and decoding <b>typed</b> variables including dates and defines the 
16290  * Provider interface.
16291  */
16292 Roo.state.Provider = function(){
16293     /**
16294      * @event statechange
16295      * Fires when a state change occurs.
16296      * @param {Provider} this This state provider
16297      * @param {String} key The state key which was changed
16298      * @param {String} value The encoded value for the state
16299      */
16300     this.addEvents({
16301         "statechange": true
16302     });
16303     this.state = {};
16304     Roo.state.Provider.superclass.constructor.call(this);
16305 };
16306 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
16307     /**
16308      * Returns the current value for a key
16309      * @param {String} name The key name
16310      * @param {Mixed} defaultValue A default value to return if the key's value is not found
16311      * @return {Mixed} The state data
16312      */
16313     get : function(name, defaultValue){
16314         return typeof this.state[name] == "undefined" ?
16315             defaultValue : this.state[name];
16316     },
16317     
16318     /**
16319      * Clears a value from the state
16320      * @param {String} name The key name
16321      */
16322     clear : function(name){
16323         delete this.state[name];
16324         this.fireEvent("statechange", this, name, null);
16325     },
16326     
16327     /**
16328      * Sets the value for a key
16329      * @param {String} name The key name
16330      * @param {Mixed} value The value to set
16331      */
16332     set : function(name, value){
16333         this.state[name] = value;
16334         this.fireEvent("statechange", this, name, value);
16335     },
16336     
16337     /**
16338      * Decodes a string previously encoded with {@link #encodeValue}.
16339      * @param {String} value The value to decode
16340      * @return {Mixed} The decoded value
16341      */
16342     decodeValue : function(cookie){
16343         var re = /^(a|n|d|b|s|o)\:(.*)$/;
16344         var matches = re.exec(unescape(cookie));
16345         if(!matches || !matches[1]) {
16346             return; // non state cookie
16347         }
16348         var type = matches[1];
16349         var v = matches[2];
16350         switch(type){
16351             case "n":
16352                 return parseFloat(v);
16353             case "d":
16354                 return new Date(Date.parse(v));
16355             case "b":
16356                 return (v == "1");
16357             case "a":
16358                 var all = [];
16359                 var values = v.split("^");
16360                 for(var i = 0, len = values.length; i < len; i++){
16361                     all.push(this.decodeValue(values[i]));
16362                 }
16363                 return all;
16364            case "o":
16365                 var all = {};
16366                 var values = v.split("^");
16367                 for(var i = 0, len = values.length; i < len; i++){
16368                     var kv = values[i].split("=");
16369                     all[kv[0]] = this.decodeValue(kv[1]);
16370                 }
16371                 return all;
16372            default:
16373                 return v;
16374         }
16375     },
16376     
16377     /**
16378      * Encodes a value including type information.  Decode with {@link #decodeValue}.
16379      * @param {Mixed} value The value to encode
16380      * @return {String} The encoded value
16381      */
16382     encodeValue : function(v){
16383         var enc;
16384         if(typeof v == "number"){
16385             enc = "n:" + v;
16386         }else if(typeof v == "boolean"){
16387             enc = "b:" + (v ? "1" : "0");
16388         }else if(v instanceof Date){
16389             enc = "d:" + v.toGMTString();
16390         }else if(v instanceof Array){
16391             var flat = "";
16392             for(var i = 0, len = v.length; i < len; i++){
16393                 flat += this.encodeValue(v[i]);
16394                 if(i != len-1) {
16395                     flat += "^";
16396                 }
16397             }
16398             enc = "a:" + flat;
16399         }else if(typeof v == "object"){
16400             var flat = "";
16401             for(var key in v){
16402                 if(typeof v[key] != "function"){
16403                     flat += key + "=" + this.encodeValue(v[key]) + "^";
16404                 }
16405             }
16406             enc = "o:" + flat.substring(0, flat.length-1);
16407         }else{
16408             enc = "s:" + v;
16409         }
16410         return escape(enc);        
16411     }
16412 });
16413
16414 /*
16415  * Based on:
16416  * Ext JS Library 1.1.1
16417  * Copyright(c) 2006-2007, Ext JS, LLC.
16418  *
16419  * Originally Released Under LGPL - original licence link has changed is not relivant.
16420  *
16421  * Fork - LGPL
16422  * <script type="text/javascript">
16423  */
16424 /**
16425  * @class Roo.state.Manager
16426  * This is the global state manager. By default all components that are "state aware" check this class
16427  * for state information if you don't pass them a custom state provider. In order for this class
16428  * to be useful, it must be initialized with a provider when your application initializes.
16429  <pre><code>
16430 // in your initialization function
16431 init : function(){
16432    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
16433    ...
16434    // supposed you have a {@link Roo.BorderLayout}
16435    var layout = new Roo.BorderLayout(...);
16436    layout.restoreState();
16437    // or a {Roo.BasicDialog}
16438    var dialog = new Roo.BasicDialog(...);
16439    dialog.restoreState();
16440  </code></pre>
16441  * @static
16442  */
16443 Roo.state.Manager = function(){
16444     var provider = new Roo.state.Provider();
16445     
16446     return {
16447         /**
16448          * Configures the default state provider for your application
16449          * @param {Provider} stateProvider The state provider to set
16450          */
16451         setProvider : function(stateProvider){
16452             provider = stateProvider;
16453         },
16454         
16455         /**
16456          * Returns the current value for a key
16457          * @param {String} name The key name
16458          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
16459          * @return {Mixed} The state data
16460          */
16461         get : function(key, defaultValue){
16462             return provider.get(key, defaultValue);
16463         },
16464         
16465         /**
16466          * Sets the value for a key
16467          * @param {String} name The key name
16468          * @param {Mixed} value The state data
16469          */
16470          set : function(key, value){
16471             provider.set(key, value);
16472         },
16473         
16474         /**
16475          * Clears a value from the state
16476          * @param {String} name The key name
16477          */
16478         clear : function(key){
16479             provider.clear(key);
16480         },
16481         
16482         /**
16483          * Gets the currently configured state provider
16484          * @return {Provider} The state provider
16485          */
16486         getProvider : function(){
16487             return provider;
16488         }
16489     };
16490 }();
16491 /*
16492  * Based on:
16493  * Ext JS Library 1.1.1
16494  * Copyright(c) 2006-2007, Ext JS, LLC.
16495  *
16496  * Originally Released Under LGPL - original licence link has changed is not relivant.
16497  *
16498  * Fork - LGPL
16499  * <script type="text/javascript">
16500  */
16501 /**
16502  * @class Roo.state.CookieProvider
16503  * @extends Roo.state.Provider
16504  * The default Provider implementation which saves state via cookies.
16505  * <br />Usage:
16506  <pre><code>
16507    var cp = new Roo.state.CookieProvider({
16508        path: "/cgi-bin/",
16509        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
16510        domain: "roojs.com"
16511    })
16512    Roo.state.Manager.setProvider(cp);
16513  </code></pre>
16514  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
16515  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
16516  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
16517  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
16518  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
16519  * domain the page is running on including the 'www' like 'www.roojs.com')
16520  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
16521  * @constructor
16522  * Create a new CookieProvider
16523  * @param {Object} config The configuration object
16524  */
16525 Roo.state.CookieProvider = function(config){
16526     Roo.state.CookieProvider.superclass.constructor.call(this);
16527     this.path = "/";
16528     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
16529     this.domain = null;
16530     this.secure = false;
16531     Roo.apply(this, config);
16532     this.state = this.readCookies();
16533 };
16534
16535 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
16536     // private
16537     set : function(name, value){
16538         if(typeof value == "undefined" || value === null){
16539             this.clear(name);
16540             return;
16541         }
16542         this.setCookie(name, value);
16543         Roo.state.CookieProvider.superclass.set.call(this, name, value);
16544     },
16545
16546     // private
16547     clear : function(name){
16548         this.clearCookie(name);
16549         Roo.state.CookieProvider.superclass.clear.call(this, name);
16550     },
16551
16552     // private
16553     readCookies : function(){
16554         var cookies = {};
16555         var c = document.cookie + ";";
16556         var re = /\s?(.*?)=(.*?);/g;
16557         var matches;
16558         while((matches = re.exec(c)) != null){
16559             var name = matches[1];
16560             var value = matches[2];
16561             if(name && name.substring(0,3) == "ys-"){
16562                 cookies[name.substr(3)] = this.decodeValue(value);
16563             }
16564         }
16565         return cookies;
16566     },
16567
16568     // private
16569     setCookie : function(name, value){
16570         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
16571            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
16572            ((this.path == null) ? "" : ("; path=" + this.path)) +
16573            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
16574            ((this.secure == true) ? "; secure" : "");
16575     },
16576
16577     // private
16578     clearCookie : function(name){
16579         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
16580            ((this.path == null) ? "" : ("; path=" + this.path)) +
16581            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
16582            ((this.secure == true) ? "; secure" : "");
16583     }
16584 });/*
16585  * Based on:
16586  * Ext JS Library 1.1.1
16587  * Copyright(c) 2006-2007, Ext JS, LLC.
16588  *
16589  * Originally Released Under LGPL - original licence link has changed is not relivant.
16590  *
16591  * Fork - LGPL
16592  * <script type="text/javascript">
16593  */
16594  
16595
16596 /**
16597  * @class Roo.ComponentMgr
16598  * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
16599  * @static
16600  */
16601 Roo.ComponentMgr = function(){
16602     var all = new Roo.util.MixedCollection();
16603
16604     return {
16605         /**
16606          * Registers a component.
16607          * @param {Roo.Component} c The component
16608          */
16609         register : function(c){
16610             all.add(c);
16611         },
16612
16613         /**
16614          * Unregisters a component.
16615          * @param {Roo.Component} c The component
16616          */
16617         unregister : function(c){
16618             all.remove(c);
16619         },
16620
16621         /**
16622          * Returns a component by id
16623          * @param {String} id The component id
16624          */
16625         get : function(id){
16626             return all.get(id);
16627         },
16628
16629         /**
16630          * Registers a function that will be called when a specified component is added to ComponentMgr
16631          * @param {String} id The component id
16632          * @param {Funtction} fn The callback function
16633          * @param {Object} scope The scope of the callback
16634          */
16635         onAvailable : function(id, fn, scope){
16636             all.on("add", function(index, o){
16637                 if(o.id == id){
16638                     fn.call(scope || o, o);
16639                     all.un("add", fn, scope);
16640                 }
16641             });
16642         }
16643     };
16644 }();/*
16645  * Based on:
16646  * Ext JS Library 1.1.1
16647  * Copyright(c) 2006-2007, Ext JS, LLC.
16648  *
16649  * Originally Released Under LGPL - original licence link has changed is not relivant.
16650  *
16651  * Fork - LGPL
16652  * <script type="text/javascript">
16653  */
16654  
16655 /**
16656  * @class Roo.Component
16657  * @extends Roo.util.Observable
16658  * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
16659  * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
16660  * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
16661  * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
16662  * All visual components (widgets) that require rendering into a layout should subclass Component.
16663  * @constructor
16664  * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
16665  * 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
16666  * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
16667  */
16668 Roo.Component = function(config){
16669     config = config || {};
16670     if(config.tagName || config.dom || typeof config == "string"){ // element object
16671         config = {el: config, id: config.id || config};
16672     }
16673     this.initialConfig = config;
16674
16675     Roo.apply(this, config);
16676     this.addEvents({
16677         /**
16678          * @event disable
16679          * Fires after the component is disabled.
16680              * @param {Roo.Component} this
16681              */
16682         disable : true,
16683         /**
16684          * @event enable
16685          * Fires after the component is enabled.
16686              * @param {Roo.Component} this
16687              */
16688         enable : true,
16689         /**
16690          * @event beforeshow
16691          * Fires before the component is shown.  Return false to stop the show.
16692              * @param {Roo.Component} this
16693              */
16694         beforeshow : true,
16695         /**
16696          * @event show
16697          * Fires after the component is shown.
16698              * @param {Roo.Component} this
16699              */
16700         show : true,
16701         /**
16702          * @event beforehide
16703          * Fires before the component is hidden. Return false to stop the hide.
16704              * @param {Roo.Component} this
16705              */
16706         beforehide : true,
16707         /**
16708          * @event hide
16709          * Fires after the component is hidden.
16710              * @param {Roo.Component} this
16711              */
16712         hide : true,
16713         /**
16714          * @event beforerender
16715          * Fires before the component is rendered. Return false to stop the render.
16716              * @param {Roo.Component} this
16717              */
16718         beforerender : true,
16719         /**
16720          * @event render
16721          * Fires after the component is rendered.
16722              * @param {Roo.Component} this
16723              */
16724         render : true,
16725         /**
16726          * @event beforedestroy
16727          * Fires before the component is destroyed. Return false to stop the destroy.
16728              * @param {Roo.Component} this
16729              */
16730         beforedestroy : true,
16731         /**
16732          * @event destroy
16733          * Fires after the component is destroyed.
16734              * @param {Roo.Component} this
16735              */
16736         destroy : true
16737     });
16738     if(!this.id){
16739         this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
16740     }
16741     Roo.ComponentMgr.register(this);
16742     Roo.Component.superclass.constructor.call(this);
16743     this.initComponent();
16744     if(this.renderTo){ // not supported by all components yet. use at your own risk!
16745         this.render(this.renderTo);
16746         delete this.renderTo;
16747     }
16748 };
16749
16750 /** @private */
16751 Roo.Component.AUTO_ID = 1000;
16752
16753 Roo.extend(Roo.Component, Roo.util.Observable, {
16754     /**
16755      * @scope Roo.Component.prototype
16756      * @type {Boolean}
16757      * true if this component is hidden. Read-only.
16758      */
16759     hidden : false,
16760     /**
16761      * @type {Boolean}
16762      * true if this component is disabled. Read-only.
16763      */
16764     disabled : false,
16765     /**
16766      * @type {Boolean}
16767      * true if this component has been rendered. Read-only.
16768      */
16769     rendered : false,
16770     
16771     /** @cfg {String} disableClass
16772      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
16773      */
16774     disabledClass : "x-item-disabled",
16775         /** @cfg {Boolean} allowDomMove
16776          * Whether the component can move the Dom node when rendering (defaults to true).
16777          */
16778     allowDomMove : true,
16779     /** @cfg {String} hideMode (display|visibility)
16780      * How this component should hidden. Supported values are
16781      * "visibility" (css visibility), "offsets" (negative offset position) and
16782      * "display" (css display) - defaults to "display".
16783      */
16784     hideMode: 'display',
16785
16786     /** @private */
16787     ctype : "Roo.Component",
16788
16789     /**
16790      * @cfg {String} actionMode 
16791      * which property holds the element that used for  hide() / show() / disable() / enable()
16792      * default is 'el' for forms you probably want to set this to fieldEl 
16793      */
16794     actionMode : "el",
16795
16796     /** @private */
16797     getActionEl : function(){
16798         return this[this.actionMode];
16799     },
16800
16801     initComponent : Roo.emptyFn,
16802     /**
16803      * If this is a lazy rendering component, render it to its container element.
16804      * @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.
16805      */
16806     render : function(container, position){
16807         
16808         if(this.rendered){
16809             return this;
16810         }
16811         
16812         if(this.fireEvent("beforerender", this) === false){
16813             return false;
16814         }
16815         
16816         if(!container && this.el){
16817             this.el = Roo.get(this.el);
16818             container = this.el.dom.parentNode;
16819             this.allowDomMove = false;
16820         }
16821         this.container = Roo.get(container);
16822         this.rendered = true;
16823         if(position !== undefined){
16824             if(typeof position == 'number'){
16825                 position = this.container.dom.childNodes[position];
16826             }else{
16827                 position = Roo.getDom(position);
16828             }
16829         }
16830         this.onRender(this.container, position || null);
16831         if(this.cls){
16832             this.el.addClass(this.cls);
16833             delete this.cls;
16834         }
16835         if(this.style){
16836             this.el.applyStyles(this.style);
16837             delete this.style;
16838         }
16839         this.fireEvent("render", this);
16840         this.afterRender(this.container);
16841         if(this.hidden){
16842             this.hide();
16843         }
16844         if(this.disabled){
16845             this.disable();
16846         }
16847
16848         return this;
16849         
16850     },
16851
16852     /** @private */
16853     // default function is not really useful
16854     onRender : function(ct, position){
16855         if(this.el){
16856             this.el = Roo.get(this.el);
16857             if(this.allowDomMove !== false){
16858                 ct.dom.insertBefore(this.el.dom, position);
16859             }
16860         }
16861     },
16862
16863     /** @private */
16864     getAutoCreate : function(){
16865         var cfg = typeof this.autoCreate == "object" ?
16866                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
16867         if(this.id && !cfg.id){
16868             cfg.id = this.id;
16869         }
16870         return cfg;
16871     },
16872
16873     /** @private */
16874     afterRender : Roo.emptyFn,
16875
16876     /**
16877      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
16878      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
16879      */
16880     destroy : function(){
16881         if(this.fireEvent("beforedestroy", this) !== false){
16882             this.purgeListeners();
16883             this.beforeDestroy();
16884             if(this.rendered){
16885                 this.el.removeAllListeners();
16886                 this.el.remove();
16887                 if(this.actionMode == "container"){
16888                     this.container.remove();
16889                 }
16890             }
16891             this.onDestroy();
16892             Roo.ComponentMgr.unregister(this);
16893             this.fireEvent("destroy", this);
16894         }
16895     },
16896
16897         /** @private */
16898     beforeDestroy : function(){
16899
16900     },
16901
16902         /** @private */
16903         onDestroy : function(){
16904
16905     },
16906
16907     /**
16908      * Returns the underlying {@link Roo.Element}.
16909      * @return {Roo.Element} The element
16910      */
16911     getEl : function(){
16912         return this.el;
16913     },
16914
16915     /**
16916      * Returns the id of this component.
16917      * @return {String}
16918      */
16919     getId : function(){
16920         return this.id;
16921     },
16922
16923     /**
16924      * Try to focus this component.
16925      * @param {Boolean} selectText True to also select the text in this component (if applicable)
16926      * @return {Roo.Component} this
16927      */
16928     focus : function(selectText){
16929         if(this.rendered){
16930             this.el.focus();
16931             if(selectText === true){
16932                 this.el.dom.select();
16933             }
16934         }
16935         return this;
16936     },
16937
16938     /** @private */
16939     blur : function(){
16940         if(this.rendered){
16941             this.el.blur();
16942         }
16943         return this;
16944     },
16945
16946     /**
16947      * Disable this component.
16948      * @return {Roo.Component} this
16949      */
16950     disable : function(){
16951         if(this.rendered){
16952             this.onDisable();
16953         }
16954         this.disabled = true;
16955         this.fireEvent("disable", this);
16956         return this;
16957     },
16958
16959         // private
16960     onDisable : function(){
16961         this.getActionEl().addClass(this.disabledClass);
16962         this.el.dom.disabled = true;
16963     },
16964
16965     /**
16966      * Enable this component.
16967      * @return {Roo.Component} this
16968      */
16969     enable : function(){
16970         if(this.rendered){
16971             this.onEnable();
16972         }
16973         this.disabled = false;
16974         this.fireEvent("enable", this);
16975         return this;
16976     },
16977
16978         // private
16979     onEnable : function(){
16980         this.getActionEl().removeClass(this.disabledClass);
16981         this.el.dom.disabled = false;
16982     },
16983
16984     /**
16985      * Convenience function for setting disabled/enabled by boolean.
16986      * @param {Boolean} disabled
16987      */
16988     setDisabled : function(disabled){
16989         this[disabled ? "disable" : "enable"]();
16990     },
16991
16992     /**
16993      * Show this component.
16994      * @return {Roo.Component} this
16995      */
16996     show: function(){
16997         if(this.fireEvent("beforeshow", this) !== false){
16998             this.hidden = false;
16999             if(this.rendered){
17000                 this.onShow();
17001             }
17002             this.fireEvent("show", this);
17003         }
17004         return this;
17005     },
17006
17007     // private
17008     onShow : function(){
17009         var ae = this.getActionEl();
17010         if(this.hideMode == 'visibility'){
17011             ae.dom.style.visibility = "visible";
17012         }else if(this.hideMode == 'offsets'){
17013             ae.removeClass('x-hidden');
17014         }else{
17015             ae.dom.style.display = "";
17016         }
17017     },
17018
17019     /**
17020      * Hide this component.
17021      * @return {Roo.Component} this
17022      */
17023     hide: function(){
17024         if(this.fireEvent("beforehide", this) !== false){
17025             this.hidden = true;
17026             if(this.rendered){
17027                 this.onHide();
17028             }
17029             this.fireEvent("hide", this);
17030         }
17031         return this;
17032     },
17033
17034     // private
17035     onHide : function(){
17036         var ae = this.getActionEl();
17037         if(this.hideMode == 'visibility'){
17038             ae.dom.style.visibility = "hidden";
17039         }else if(this.hideMode == 'offsets'){
17040             ae.addClass('x-hidden');
17041         }else{
17042             ae.dom.style.display = "none";
17043         }
17044     },
17045
17046     /**
17047      * Convenience function to hide or show this component by boolean.
17048      * @param {Boolean} visible True to show, false to hide
17049      * @return {Roo.Component} this
17050      */
17051     setVisible: function(visible){
17052         if(visible) {
17053             this.show();
17054         }else{
17055             this.hide();
17056         }
17057         return this;
17058     },
17059
17060     /**
17061      * Returns true if this component is visible.
17062      */
17063     isVisible : function(){
17064         return this.getActionEl().isVisible();
17065     },
17066
17067     cloneConfig : function(overrides){
17068         overrides = overrides || {};
17069         var id = overrides.id || Roo.id();
17070         var cfg = Roo.applyIf(overrides, this.initialConfig);
17071         cfg.id = id; // prevent dup id
17072         return new this.constructor(cfg);
17073     }
17074 });/*
17075  * Based on:
17076  * Ext JS Library 1.1.1
17077  * Copyright(c) 2006-2007, Ext JS, LLC.
17078  *
17079  * Originally Released Under LGPL - original licence link has changed is not relivant.
17080  *
17081  * Fork - LGPL
17082  * <script type="text/javascript">
17083  */
17084
17085 /**
17086  * @class Roo.BoxComponent
17087  * @extends Roo.Component
17088  * Base class for any visual {@link Roo.Component} that uses a box container.  BoxComponent provides automatic box
17089  * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model.  All
17090  * container classes should subclass BoxComponent so that they will work consistently when nested within other Roo
17091  * layout containers.
17092  * @constructor
17093  * @param {Roo.Element/String/Object} config The configuration options.
17094  */
17095 Roo.BoxComponent = function(config){
17096     Roo.Component.call(this, config);
17097     this.addEvents({
17098         /**
17099          * @event resize
17100          * Fires after the component is resized.
17101              * @param {Roo.Component} this
17102              * @param {Number} adjWidth The box-adjusted width that was set
17103              * @param {Number} adjHeight The box-adjusted height that was set
17104              * @param {Number} rawWidth The width that was originally specified
17105              * @param {Number} rawHeight The height that was originally specified
17106              */
17107         resize : true,
17108         /**
17109          * @event move
17110          * Fires after the component is moved.
17111              * @param {Roo.Component} this
17112              * @param {Number} x The new x position
17113              * @param {Number} y The new y position
17114              */
17115         move : true
17116     });
17117 };
17118
17119 Roo.extend(Roo.BoxComponent, Roo.Component, {
17120     // private, set in afterRender to signify that the component has been rendered
17121     boxReady : false,
17122     // private, used to defer height settings to subclasses
17123     deferHeight: false,
17124     /** @cfg {Number} width
17125      * width (optional) size of component
17126      */
17127      /** @cfg {Number} height
17128      * height (optional) size of component
17129      */
17130      
17131     /**
17132      * Sets the width and height of the component.  This method fires the resize event.  This method can accept
17133      * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
17134      * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
17135      * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
17136      * @return {Roo.BoxComponent} this
17137      */
17138     setSize : function(w, h){
17139         // support for standard size objects
17140         if(typeof w == 'object'){
17141             h = w.height;
17142             w = w.width;
17143         }
17144         // not rendered
17145         if(!this.boxReady){
17146             this.width = w;
17147             this.height = h;
17148             return this;
17149         }
17150
17151         // prevent recalcs when not needed
17152         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
17153             return this;
17154         }
17155         this.lastSize = {width: w, height: h};
17156
17157         var adj = this.adjustSize(w, h);
17158         var aw = adj.width, ah = adj.height;
17159         if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
17160             var rz = this.getResizeEl();
17161             if(!this.deferHeight && aw !== undefined && ah !== undefined){
17162                 rz.setSize(aw, ah);
17163             }else if(!this.deferHeight && ah !== undefined){
17164                 rz.setHeight(ah);
17165             }else if(aw !== undefined){
17166                 rz.setWidth(aw);
17167             }
17168             this.onResize(aw, ah, w, h);
17169             this.fireEvent('resize', this, aw, ah, w, h);
17170         }
17171         return this;
17172     },
17173
17174     /**
17175      * Gets the current size of the component's underlying element.
17176      * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
17177      */
17178     getSize : function(){
17179         return this.el.getSize();
17180     },
17181
17182     /**
17183      * Gets the current XY position of the component's underlying element.
17184      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
17185      * @return {Array} The XY position of the element (e.g., [100, 200])
17186      */
17187     getPosition : function(local){
17188         if(local === true){
17189             return [this.el.getLeft(true), this.el.getTop(true)];
17190         }
17191         return this.xy || this.el.getXY();
17192     },
17193
17194     /**
17195      * Gets the current box measurements of the component's underlying element.
17196      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
17197      * @returns {Object} box An object in the format {x, y, width, height}
17198      */
17199     getBox : function(local){
17200         var s = this.el.getSize();
17201         if(local){
17202             s.x = this.el.getLeft(true);
17203             s.y = this.el.getTop(true);
17204         }else{
17205             var xy = this.xy || this.el.getXY();
17206             s.x = xy[0];
17207             s.y = xy[1];
17208         }
17209         return s;
17210     },
17211
17212     /**
17213      * Sets the current box measurements of the component's underlying element.
17214      * @param {Object} box An object in the format {x, y, width, height}
17215      * @returns {Roo.BoxComponent} this
17216      */
17217     updateBox : function(box){
17218         this.setSize(box.width, box.height);
17219         this.setPagePosition(box.x, box.y);
17220         return this;
17221     },
17222
17223     // protected
17224     getResizeEl : function(){
17225         return this.resizeEl || this.el;
17226     },
17227
17228     // protected
17229     getPositionEl : function(){
17230         return this.positionEl || this.el;
17231     },
17232
17233     /**
17234      * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
17235      * This method fires the move event.
17236      * @param {Number} left The new left
17237      * @param {Number} top The new top
17238      * @returns {Roo.BoxComponent} this
17239      */
17240     setPosition : function(x, y){
17241         this.x = x;
17242         this.y = y;
17243         if(!this.boxReady){
17244             return this;
17245         }
17246         var adj = this.adjustPosition(x, y);
17247         var ax = adj.x, ay = adj.y;
17248
17249         var el = this.getPositionEl();
17250         if(ax !== undefined || ay !== undefined){
17251             if(ax !== undefined && ay !== undefined){
17252                 el.setLeftTop(ax, ay);
17253             }else if(ax !== undefined){
17254                 el.setLeft(ax);
17255             }else if(ay !== undefined){
17256                 el.setTop(ay);
17257             }
17258             this.onPosition(ax, ay);
17259             this.fireEvent('move', this, ax, ay);
17260         }
17261         return this;
17262     },
17263
17264     /**
17265      * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
17266      * This method fires the move event.
17267      * @param {Number} x The new x position
17268      * @param {Number} y The new y position
17269      * @returns {Roo.BoxComponent} this
17270      */
17271     setPagePosition : function(x, y){
17272         this.pageX = x;
17273         this.pageY = y;
17274         if(!this.boxReady){
17275             return;
17276         }
17277         if(x === undefined || y === undefined){ // cannot translate undefined points
17278             return;
17279         }
17280         var p = this.el.translatePoints(x, y);
17281         this.setPosition(p.left, p.top);
17282         return this;
17283     },
17284
17285     // private
17286     onRender : function(ct, position){
17287         Roo.BoxComponent.superclass.onRender.call(this, ct, position);
17288         if(this.resizeEl){
17289             this.resizeEl = Roo.get(this.resizeEl);
17290         }
17291         if(this.positionEl){
17292             this.positionEl = Roo.get(this.positionEl);
17293         }
17294     },
17295
17296     // private
17297     afterRender : function(){
17298         Roo.BoxComponent.superclass.afterRender.call(this);
17299         this.boxReady = true;
17300         this.setSize(this.width, this.height);
17301         if(this.x || this.y){
17302             this.setPosition(this.x, this.y);
17303         }
17304         if(this.pageX || this.pageY){
17305             this.setPagePosition(this.pageX, this.pageY);
17306         }
17307     },
17308
17309     /**
17310      * Force the component's size to recalculate based on the underlying element's current height and width.
17311      * @returns {Roo.BoxComponent} this
17312      */
17313     syncSize : function(){
17314         delete this.lastSize;
17315         this.setSize(this.el.getWidth(), this.el.getHeight());
17316         return this;
17317     },
17318
17319     /**
17320      * Called after the component is resized, this method is empty by default but can be implemented by any
17321      * subclass that needs to perform custom logic after a resize occurs.
17322      * @param {Number} adjWidth The box-adjusted width that was set
17323      * @param {Number} adjHeight The box-adjusted height that was set
17324      * @param {Number} rawWidth The width that was originally specified
17325      * @param {Number} rawHeight The height that was originally specified
17326      */
17327     onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
17328
17329     },
17330
17331     /**
17332      * Called after the component is moved, this method is empty by default but can be implemented by any
17333      * subclass that needs to perform custom logic after a move occurs.
17334      * @param {Number} x The new x position
17335      * @param {Number} y The new y position
17336      */
17337     onPosition : function(x, y){
17338
17339     },
17340
17341     // private
17342     adjustSize : function(w, h){
17343         if(this.autoWidth){
17344             w = 'auto';
17345         }
17346         if(this.autoHeight){
17347             h = 'auto';
17348         }
17349         return {width : w, height: h};
17350     },
17351
17352     // private
17353     adjustPosition : function(x, y){
17354         return {x : x, y: y};
17355     }
17356 });/*
17357  * Based on:
17358  * Ext JS Library 1.1.1
17359  * Copyright(c) 2006-2007, Ext JS, LLC.
17360  *
17361  * Originally Released Under LGPL - original licence link has changed is not relivant.
17362  *
17363  * Fork - LGPL
17364  * <script type="text/javascript">
17365  */
17366  (function(){ 
17367 /**
17368  * @class Roo.Layer
17369  * @extends Roo.Element
17370  * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
17371  * automatic maintaining of shadow/shim positions.
17372  * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
17373  * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
17374  * you can pass a string with a CSS class name. False turns off the shadow.
17375  * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
17376  * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
17377  * @cfg {String} cls CSS class to add to the element
17378  * @cfg {Number} zindex Starting z-index (defaults to 11000)
17379  * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
17380  * @constructor
17381  * @param {Object} config An object with config options.
17382  * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
17383  */
17384
17385 Roo.Layer = function(config, existingEl){
17386     config = config || {};
17387     var dh = Roo.DomHelper;
17388     var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
17389     if(existingEl){
17390         this.dom = Roo.getDom(existingEl);
17391     }
17392     if(!this.dom){
17393         var o = config.dh || {tag: "div", cls: "x-layer"};
17394         this.dom = dh.append(pel, o);
17395     }
17396     if(config.cls){
17397         this.addClass(config.cls);
17398     }
17399     this.constrain = config.constrain !== false;
17400     this.visibilityMode = Roo.Element.VISIBILITY;
17401     if(config.id){
17402         this.id = this.dom.id = config.id;
17403     }else{
17404         this.id = Roo.id(this.dom);
17405     }
17406     this.zindex = config.zindex || this.getZIndex();
17407     this.position("absolute", this.zindex);
17408     if(config.shadow){
17409         this.shadowOffset = config.shadowOffset || 4;
17410         this.shadow = new Roo.Shadow({
17411             offset : this.shadowOffset,
17412             mode : config.shadow
17413         });
17414     }else{
17415         this.shadowOffset = 0;
17416     }
17417     this.useShim = config.shim !== false && Roo.useShims;
17418     this.useDisplay = config.useDisplay;
17419     this.hide();
17420 };
17421
17422 var supr = Roo.Element.prototype;
17423
17424 // shims are shared among layer to keep from having 100 iframes
17425 var shims = [];
17426
17427 Roo.extend(Roo.Layer, Roo.Element, {
17428
17429     getZIndex : function(){
17430         return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
17431     },
17432
17433     getShim : function(){
17434         if(!this.useShim){
17435             return null;
17436         }
17437         if(this.shim){
17438             return this.shim;
17439         }
17440         var shim = shims.shift();
17441         if(!shim){
17442             shim = this.createShim();
17443             shim.enableDisplayMode('block');
17444             shim.dom.style.display = 'none';
17445             shim.dom.style.visibility = 'visible';
17446         }
17447         var pn = this.dom.parentNode;
17448         if(shim.dom.parentNode != pn){
17449             pn.insertBefore(shim.dom, this.dom);
17450         }
17451         shim.setStyle('z-index', this.getZIndex()-2);
17452         this.shim = shim;
17453         return shim;
17454     },
17455
17456     hideShim : function(){
17457         if(this.shim){
17458             this.shim.setDisplayed(false);
17459             shims.push(this.shim);
17460             delete this.shim;
17461         }
17462     },
17463
17464     disableShadow : function(){
17465         if(this.shadow){
17466             this.shadowDisabled = true;
17467             this.shadow.hide();
17468             this.lastShadowOffset = this.shadowOffset;
17469             this.shadowOffset = 0;
17470         }
17471     },
17472
17473     enableShadow : function(show){
17474         if(this.shadow){
17475             this.shadowDisabled = false;
17476             this.shadowOffset = this.lastShadowOffset;
17477             delete this.lastShadowOffset;
17478             if(show){
17479                 this.sync(true);
17480             }
17481         }
17482     },
17483
17484     // private
17485     // this code can execute repeatedly in milliseconds (i.e. during a drag) so
17486     // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
17487     sync : function(doShow){
17488         var sw = this.shadow;
17489         if(!this.updating && this.isVisible() && (sw || this.useShim)){
17490             var sh = this.getShim();
17491
17492             var w = this.getWidth(),
17493                 h = this.getHeight();
17494
17495             var l = this.getLeft(true),
17496                 t = this.getTop(true);
17497
17498             if(sw && !this.shadowDisabled){
17499                 if(doShow && !sw.isVisible()){
17500                     sw.show(this);
17501                 }else{
17502                     sw.realign(l, t, w, h);
17503                 }
17504                 if(sh){
17505                     if(doShow){
17506                        sh.show();
17507                     }
17508                     // fit the shim behind the shadow, so it is shimmed too
17509                     var a = sw.adjusts, s = sh.dom.style;
17510                     s.left = (Math.min(l, l+a.l))+"px";
17511                     s.top = (Math.min(t, t+a.t))+"px";
17512                     s.width = (w+a.w)+"px";
17513                     s.height = (h+a.h)+"px";
17514                 }
17515             }else if(sh){
17516                 if(doShow){
17517                    sh.show();
17518                 }
17519                 sh.setSize(w, h);
17520                 sh.setLeftTop(l, t);
17521             }
17522             
17523         }
17524     },
17525
17526     // private
17527     destroy : function(){
17528         this.hideShim();
17529         if(this.shadow){
17530             this.shadow.hide();
17531         }
17532         this.removeAllListeners();
17533         var pn = this.dom.parentNode;
17534         if(pn){
17535             pn.removeChild(this.dom);
17536         }
17537         Roo.Element.uncache(this.id);
17538     },
17539
17540     remove : function(){
17541         this.destroy();
17542     },
17543
17544     // private
17545     beginUpdate : function(){
17546         this.updating = true;
17547     },
17548
17549     // private
17550     endUpdate : function(){
17551         this.updating = false;
17552         this.sync(true);
17553     },
17554
17555     // private
17556     hideUnders : function(negOffset){
17557         if(this.shadow){
17558             this.shadow.hide();
17559         }
17560         this.hideShim();
17561     },
17562
17563     // private
17564     constrainXY : function(){
17565         if(this.constrain){
17566             var vw = Roo.lib.Dom.getViewWidth(),
17567                 vh = Roo.lib.Dom.getViewHeight();
17568             var s = Roo.get(document).getScroll();
17569
17570             var xy = this.getXY();
17571             var x = xy[0], y = xy[1];   
17572             var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
17573             // only move it if it needs it
17574             var moved = false;
17575             // first validate right/bottom
17576             if((x + w) > vw+s.left){
17577                 x = vw - w - this.shadowOffset;
17578                 moved = true;
17579             }
17580             if((y + h) > vh+s.top){
17581                 y = vh - h - this.shadowOffset;
17582                 moved = true;
17583             }
17584             // then make sure top/left isn't negative
17585             if(x < s.left){
17586                 x = s.left;
17587                 moved = true;
17588             }
17589             if(y < s.top){
17590                 y = s.top;
17591                 moved = true;
17592             }
17593             if(moved){
17594                 if(this.avoidY){
17595                     var ay = this.avoidY;
17596                     if(y <= ay && (y+h) >= ay){
17597                         y = ay-h-5;   
17598                     }
17599                 }
17600                 xy = [x, y];
17601                 this.storeXY(xy);
17602                 supr.setXY.call(this, xy);
17603                 this.sync();
17604             }
17605         }
17606     },
17607
17608     isVisible : function(){
17609         return this.visible;    
17610     },
17611
17612     // private
17613     showAction : function(){
17614         this.visible = true; // track visibility to prevent getStyle calls
17615         if(this.useDisplay === true){
17616             this.setDisplayed("");
17617         }else if(this.lastXY){
17618             supr.setXY.call(this, this.lastXY);
17619         }else if(this.lastLT){
17620             supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
17621         }
17622     },
17623
17624     // private
17625     hideAction : function(){
17626         this.visible = false;
17627         if(this.useDisplay === true){
17628             this.setDisplayed(false);
17629         }else{
17630             this.setLeftTop(-10000,-10000);
17631         }
17632     },
17633
17634     // overridden Element method
17635     setVisible : function(v, a, d, c, e){
17636         if(v){
17637             this.showAction();
17638         }
17639         if(a && v){
17640             var cb = function(){
17641                 this.sync(true);
17642                 if(c){
17643                     c();
17644                 }
17645             }.createDelegate(this);
17646             supr.setVisible.call(this, true, true, d, cb, e);
17647         }else{
17648             if(!v){
17649                 this.hideUnders(true);
17650             }
17651             var cb = c;
17652             if(a){
17653                 cb = function(){
17654                     this.hideAction();
17655                     if(c){
17656                         c();
17657                     }
17658                 }.createDelegate(this);
17659             }
17660             supr.setVisible.call(this, v, a, d, cb, e);
17661             if(v){
17662                 this.sync(true);
17663             }else if(!a){
17664                 this.hideAction();
17665             }
17666         }
17667     },
17668
17669     storeXY : function(xy){
17670         delete this.lastLT;
17671         this.lastXY = xy;
17672     },
17673
17674     storeLeftTop : function(left, top){
17675         delete this.lastXY;
17676         this.lastLT = [left, top];
17677     },
17678
17679     // private
17680     beforeFx : function(){
17681         this.beforeAction();
17682         return Roo.Layer.superclass.beforeFx.apply(this, arguments);
17683     },
17684
17685     // private
17686     afterFx : function(){
17687         Roo.Layer.superclass.afterFx.apply(this, arguments);
17688         this.sync(this.isVisible());
17689     },
17690
17691     // private
17692     beforeAction : function(){
17693         if(!this.updating && this.shadow){
17694             this.shadow.hide();
17695         }
17696     },
17697
17698     // overridden Element method
17699     setLeft : function(left){
17700         this.storeLeftTop(left, this.getTop(true));
17701         supr.setLeft.apply(this, arguments);
17702         this.sync();
17703     },
17704
17705     setTop : function(top){
17706         this.storeLeftTop(this.getLeft(true), top);
17707         supr.setTop.apply(this, arguments);
17708         this.sync();
17709     },
17710
17711     setLeftTop : function(left, top){
17712         this.storeLeftTop(left, top);
17713         supr.setLeftTop.apply(this, arguments);
17714         this.sync();
17715     },
17716
17717     setXY : function(xy, a, d, c, e){
17718         this.fixDisplay();
17719         this.beforeAction();
17720         this.storeXY(xy);
17721         var cb = this.createCB(c);
17722         supr.setXY.call(this, xy, a, d, cb, e);
17723         if(!a){
17724             cb();
17725         }
17726     },
17727
17728     // private
17729     createCB : function(c){
17730         var el = this;
17731         return function(){
17732             el.constrainXY();
17733             el.sync(true);
17734             if(c){
17735                 c();
17736             }
17737         };
17738     },
17739
17740     // overridden Element method
17741     setX : function(x, a, d, c, e){
17742         this.setXY([x, this.getY()], a, d, c, e);
17743     },
17744
17745     // overridden Element method
17746     setY : function(y, a, d, c, e){
17747         this.setXY([this.getX(), y], a, d, c, e);
17748     },
17749
17750     // overridden Element method
17751     setSize : function(w, h, a, d, c, e){
17752         this.beforeAction();
17753         var cb = this.createCB(c);
17754         supr.setSize.call(this, w, h, a, d, cb, e);
17755         if(!a){
17756             cb();
17757         }
17758     },
17759
17760     // overridden Element method
17761     setWidth : function(w, a, d, c, e){
17762         this.beforeAction();
17763         var cb = this.createCB(c);
17764         supr.setWidth.call(this, w, a, d, cb, e);
17765         if(!a){
17766             cb();
17767         }
17768     },
17769
17770     // overridden Element method
17771     setHeight : function(h, a, d, c, e){
17772         this.beforeAction();
17773         var cb = this.createCB(c);
17774         supr.setHeight.call(this, h, a, d, cb, e);
17775         if(!a){
17776             cb();
17777         }
17778     },
17779
17780     // overridden Element method
17781     setBounds : function(x, y, w, h, a, d, c, e){
17782         this.beforeAction();
17783         var cb = this.createCB(c);
17784         if(!a){
17785             this.storeXY([x, y]);
17786             supr.setXY.call(this, [x, y]);
17787             supr.setSize.call(this, w, h, a, d, cb, e);
17788             cb();
17789         }else{
17790             supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
17791         }
17792         return this;
17793     },
17794     
17795     /**
17796      * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
17797      * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
17798      * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
17799      * @param {Number} zindex The new z-index to set
17800      * @return {this} The Layer
17801      */
17802     setZIndex : function(zindex){
17803         this.zindex = zindex;
17804         this.setStyle("z-index", zindex + 2);
17805         if(this.shadow){
17806             this.shadow.setZIndex(zindex + 1);
17807         }
17808         if(this.shim){
17809             this.shim.setStyle("z-index", zindex);
17810         }
17811     }
17812 });
17813 })();/*
17814  * Original code for Roojs - LGPL
17815  * <script type="text/javascript">
17816  */
17817  
17818 /**
17819  * @class Roo.XComponent
17820  * A delayed Element creator...
17821  * Or a way to group chunks of interface together.
17822  * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
17823  *  used in conjunction with XComponent.build() it will create an instance of each element,
17824  *  then call addxtype() to build the User interface.
17825  * 
17826  * Mypart.xyx = new Roo.XComponent({
17827
17828     parent : 'Mypart.xyz', // empty == document.element.!!
17829     order : '001',
17830     name : 'xxxx'
17831     region : 'xxxx'
17832     disabled : function() {} 
17833      
17834     tree : function() { // return an tree of xtype declared components
17835         var MODULE = this;
17836         return 
17837         {
17838             xtype : 'NestedLayoutPanel',
17839             // technicall
17840         }
17841      ]
17842  *})
17843  *
17844  *
17845  * It can be used to build a big heiracy, with parent etc.
17846  * or you can just use this to render a single compoent to a dom element
17847  * MYPART.render(Roo.Element | String(id) | dom_element )
17848  *
17849  *
17850  * Usage patterns.
17851  *
17852  * Classic Roo
17853  *
17854  * Roo is designed primarily as a single page application, so the UI build for a standard interface will
17855  * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
17856  *
17857  * Each sub module is expected to have a parent pointing to the class name of it's parent module.
17858  *
17859  * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
17860  * - if mulitple topModules exist, the last one is defined as the top module.
17861  *
17862  * Embeded Roo
17863  * 
17864  * When the top level or multiple modules are to embedded into a existing HTML page,
17865  * the parent element can container '#id' of the element where the module will be drawn.
17866  *
17867  * Bootstrap Roo
17868  *
17869  * Unlike classic Roo, the bootstrap tends not to be used as a single page.
17870  * it relies more on a include mechanism, where sub modules are included into an outer page.
17871  * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
17872  * 
17873  * Bootstrap Roo Included elements
17874  *
17875  * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
17876  * hence confusing the component builder as it thinks there are multiple top level elements. 
17877  *
17878  * String Over-ride & Translations
17879  *
17880  * Our builder application writes all the strings as _strings and _named_strings. This is to enable the translation of elements,
17881  * and also the 'overlaying of string values - needed when different versions of the same application with different text content
17882  * are needed. @see Roo.XComponent.overlayString  
17883  * 
17884  * 
17885  * 
17886  * @extends Roo.util.Observable
17887  * @constructor
17888  * @param cfg {Object} configuration of component
17889  * 
17890  */
17891 Roo.XComponent = function(cfg) {
17892     Roo.apply(this, cfg);
17893     this.addEvents({ 
17894         /**
17895              * @event built
17896              * Fires when this the componnt is built
17897              * @param {Roo.XComponent} c the component
17898              */
17899         'built' : true
17900         
17901     });
17902     this.region = this.region || 'center'; // default..
17903     Roo.XComponent.register(this);
17904     this.modules = false;
17905     this.el = false; // where the layout goes..
17906     
17907     
17908 }
17909 Roo.extend(Roo.XComponent, Roo.util.Observable, {
17910     /**
17911      * @property el
17912      * The created element (with Roo.factory())
17913      * @type {Roo.Layout}
17914      */
17915     el  : false,
17916     
17917     /**
17918      * @property el
17919      * for BC  - use el in new code
17920      * @type {Roo.Layout}
17921      */
17922     panel : false,
17923     
17924     /**
17925      * @property layout
17926      * for BC  - use el in new code
17927      * @type {Roo.Layout}
17928      */
17929     layout : false,
17930     
17931      /**
17932      * @cfg {Function|boolean} disabled
17933      * If this module is disabled by some rule, return true from the funtion
17934      */
17935     disabled : false,
17936     
17937     /**
17938      * @cfg {String} parent 
17939      * Name of parent element which it get xtype added to..
17940      */
17941     parent: false,
17942     
17943     /**
17944      * @cfg {String} order
17945      * Used to set the order in which elements are created (usefull for multiple tabs)
17946      */
17947     
17948     order : false,
17949     /**
17950      * @cfg {String} name
17951      * String to display while loading.
17952      */
17953     name : false,
17954     /**
17955      * @cfg {String} region
17956      * Region to render component to (defaults to center)
17957      */
17958     region : 'center',
17959     
17960     /**
17961      * @cfg {Array} items
17962      * A single item array - the first element is the root of the tree..
17963      * It's done this way to stay compatible with the Xtype system...
17964      */
17965     items : false,
17966     
17967     /**
17968      * @property _tree
17969      * The method that retuns the tree of parts that make up this compoennt 
17970      * @type {function}
17971      */
17972     _tree  : false,
17973     
17974      /**
17975      * render
17976      * render element to dom or tree
17977      * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
17978      */
17979     
17980     render : function(el)
17981     {
17982         
17983         el = el || false;
17984         var hp = this.parent ? 1 : 0;
17985         Roo.debug &&  Roo.log(this);
17986         
17987         var tree = this._tree ? this._tree() : this.tree();
17988
17989         
17990         if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
17991             // if parent is a '#.....' string, then let's use that..
17992             var ename = this.parent.substr(1);
17993             this.parent = false;
17994             Roo.debug && Roo.log(ename);
17995             switch (ename) {
17996                 case 'bootstrap-body':
17997                     if (typeof(tree.el) != 'undefined' && tree.el == document.body)  {
17998                         // this is the BorderLayout standard?
17999                        this.parent = { el : true };
18000                        break;
18001                     }
18002                     if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype)  > -1)  {
18003                         // need to insert stuff...
18004                         this.parent =  {
18005                              el : new Roo.bootstrap.layout.Border({
18006                                  el : document.body, 
18007                      
18008                                  center: {
18009                                     titlebar: false,
18010                                     autoScroll:false,
18011                                     closeOnTab: true,
18012                                     tabPosition: 'top',
18013                                       //resizeTabs: true,
18014                                     alwaysShowTabs: true,
18015                                     hideTabs: false
18016                                      //minTabWidth: 140
18017                                  }
18018                              })
18019                         
18020                          };
18021                          break;
18022                     }
18023                          
18024                     if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
18025                         this.parent = { el :  new  Roo.bootstrap.Body() };
18026                         Roo.debug && Roo.log("setting el to doc body");
18027                          
18028                     } else {
18029                         throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
18030                     }
18031                     break;
18032                 case 'bootstrap':
18033                     this.parent = { el : true};
18034                     // fall through
18035                 default:
18036                     el = Roo.get(ename);
18037                     if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
18038                         this.parent = { el : true};
18039                     }
18040                     
18041                     break;
18042             }
18043                 
18044             
18045             if (!el && !this.parent) {
18046                 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
18047                 return;
18048             }
18049         }
18050         
18051         Roo.debug && Roo.log("EL:");
18052         Roo.debug && Roo.log(el);
18053         Roo.debug && Roo.log("this.parent.el:");
18054         Roo.debug && Roo.log(this.parent.el);
18055         
18056
18057         // altertive root elements ??? - we need a better way to indicate these.
18058         var is_alt = Roo.XComponent.is_alt ||
18059                     (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
18060                     (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
18061                     (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
18062         
18063         
18064         
18065         if (!this.parent && is_alt) {
18066             //el = Roo.get(document.body);
18067             this.parent = { el : true };
18068         }
18069             
18070             
18071         
18072         if (!this.parent) {
18073             
18074             Roo.debug && Roo.log("no parent - creating one");
18075             
18076             el = el ? Roo.get(el) : false;      
18077             
18078             if (typeof(Roo.BorderLayout) == 'undefined' ) {
18079                 
18080                 this.parent =  {
18081                     el : new Roo.bootstrap.layout.Border({
18082                         el: el || document.body,
18083                     
18084                         center: {
18085                             titlebar: false,
18086                             autoScroll:false,
18087                             closeOnTab: true,
18088                             tabPosition: 'top',
18089                              //resizeTabs: true,
18090                             alwaysShowTabs: false,
18091                             hideTabs: true,
18092                             minTabWidth: 140,
18093                             overflow: 'visible'
18094                          }
18095                      })
18096                 };
18097             } else {
18098             
18099                 // it's a top level one..
18100                 this.parent =  {
18101                     el : new Roo.BorderLayout(el || document.body, {
18102                         center: {
18103                             titlebar: false,
18104                             autoScroll:false,
18105                             closeOnTab: true,
18106                             tabPosition: 'top',
18107                              //resizeTabs: true,
18108                             alwaysShowTabs: el && hp? false :  true,
18109                             hideTabs: el || !hp ? true :  false,
18110                             minTabWidth: 140
18111                          }
18112                     })
18113                 };
18114             }
18115         }
18116         
18117         if (!this.parent.el) {
18118                 // probably an old style ctor, which has been disabled.
18119                 return;
18120
18121         }
18122                 // The 'tree' method is  '_tree now' 
18123             
18124         tree.region = tree.region || this.region;
18125         var is_body = false;
18126         if (this.parent.el === true) {
18127             // bootstrap... - body..
18128             if (el) {
18129                 tree.el = el;
18130             }
18131             this.parent.el = Roo.factory(tree);
18132             is_body = true;
18133         }
18134         
18135         this.el = this.parent.el.addxtype(tree, undefined, is_body);
18136         this.fireEvent('built', this);
18137         
18138         this.panel = this.el;
18139         this.layout = this.panel.layout;
18140         this.parentLayout = this.parent.layout  || false;  
18141          
18142     }
18143     
18144 });
18145
18146 Roo.apply(Roo.XComponent, {
18147     /**
18148      * @property  hideProgress
18149      * true to disable the building progress bar.. usefull on single page renders.
18150      * @type Boolean
18151      */
18152     hideProgress : false,
18153     /**
18154      * @property  buildCompleted
18155      * True when the builder has completed building the interface.
18156      * @type Boolean
18157      */
18158     buildCompleted : false,
18159      
18160     /**
18161      * @property  topModule
18162      * the upper most module - uses document.element as it's constructor.
18163      * @type Object
18164      */
18165      
18166     topModule  : false,
18167       
18168     /**
18169      * @property  modules
18170      * array of modules to be created by registration system.
18171      * @type {Array} of Roo.XComponent
18172      */
18173     
18174     modules : [],
18175     /**
18176      * @property  elmodules
18177      * array of modules to be created by which use #ID 
18178      * @type {Array} of Roo.XComponent
18179      */
18180      
18181     elmodules : [],
18182
18183      /**
18184      * @property  is_alt
18185      * Is an alternative Root - normally used by bootstrap or other systems,
18186      *    where the top element in the tree can wrap 'body' 
18187      * @type {boolean}  (default false)
18188      */
18189      
18190     is_alt : false,
18191     /**
18192      * @property  build_from_html
18193      * Build elements from html - used by bootstrap HTML stuff 
18194      *    - this is cleared after build is completed
18195      * @type {boolean}    (default false)
18196      */
18197      
18198     build_from_html : false,
18199     /**
18200      * Register components to be built later.
18201      *
18202      * This solves the following issues
18203      * - Building is not done on page load, but after an authentication process has occured.
18204      * - Interface elements are registered on page load
18205      * - Parent Interface elements may not be loaded before child, so this handles that..
18206      * 
18207      *
18208      * example:
18209      * 
18210      * MyApp.register({
18211           order : '000001',
18212           module : 'Pman.Tab.projectMgr',
18213           region : 'center',
18214           parent : 'Pman.layout',
18215           disabled : false,  // or use a function..
18216         })
18217      
18218      * * @param {Object} details about module
18219      */
18220     register : function(obj) {
18221                 
18222         Roo.XComponent.event.fireEvent('register', obj);
18223         switch(typeof(obj.disabled) ) {
18224                 
18225             case 'undefined':
18226                 break;
18227             
18228             case 'function':
18229                 if ( obj.disabled() ) {
18230                         return;
18231                 }
18232                 break;
18233             
18234             default:
18235                 if (obj.disabled || obj.region == '#disabled') {
18236                         return;
18237                 }
18238                 break;
18239         }
18240                 
18241         this.modules.push(obj);
18242          
18243     },
18244     /**
18245      * convert a string to an object..
18246      * eg. 'AAA.BBB' -> finds AAA.BBB
18247
18248      */
18249     
18250     toObject : function(str)
18251     {
18252         if (!str || typeof(str) == 'object') {
18253             return str;
18254         }
18255         if (str.substring(0,1) == '#') {
18256             return str;
18257         }
18258
18259         var ar = str.split('.');
18260         var rt, o;
18261         rt = ar.shift();
18262             /** eval:var:o */
18263         try {
18264             eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
18265         } catch (e) {
18266             throw "Module not found : " + str;
18267         }
18268         
18269         if (o === false) {
18270             throw "Module not found : " + str;
18271         }
18272         Roo.each(ar, function(e) {
18273             if (typeof(o[e]) == 'undefined') {
18274                 throw "Module not found : " + str;
18275             }
18276             o = o[e];
18277         });
18278         
18279         return o;
18280         
18281     },
18282     
18283     
18284     /**
18285      * move modules into their correct place in the tree..
18286      * 
18287      */
18288     preBuild : function ()
18289     {
18290         var _t = this;
18291         Roo.each(this.modules , function (obj)
18292         {
18293             Roo.XComponent.event.fireEvent('beforebuild', obj);
18294             
18295             var opar = obj.parent;
18296             try { 
18297                 obj.parent = this.toObject(opar);
18298             } catch(e) {
18299                 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
18300                 return;
18301             }
18302             
18303             if (!obj.parent) {
18304                 Roo.debug && Roo.log("GOT top level module");
18305                 Roo.debug && Roo.log(obj);
18306                 obj.modules = new Roo.util.MixedCollection(false, 
18307                     function(o) { return o.order + '' }
18308                 );
18309                 this.topModule = obj;
18310                 return;
18311             }
18312                         // parent is a string (usually a dom element name..)
18313             if (typeof(obj.parent) == 'string') {
18314                 this.elmodules.push(obj);
18315                 return;
18316             }
18317             if (obj.parent.constructor != Roo.XComponent) {
18318                 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
18319             }
18320             if (!obj.parent.modules) {
18321                 obj.parent.modules = new Roo.util.MixedCollection(false, 
18322                     function(o) { return o.order + '' }
18323                 );
18324             }
18325             if (obj.parent.disabled) {
18326                 obj.disabled = true;
18327             }
18328             obj.parent.modules.add(obj);
18329         }, this);
18330     },
18331     
18332      /**
18333      * make a list of modules to build.
18334      * @return {Array} list of modules. 
18335      */ 
18336     
18337     buildOrder : function()
18338     {
18339         var _this = this;
18340         var cmp = function(a,b) {   
18341             return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
18342         };
18343         if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
18344             throw "No top level modules to build";
18345         }
18346         
18347         // make a flat list in order of modules to build.
18348         var mods = this.topModule ? [ this.topModule ] : [];
18349                 
18350         
18351         // elmodules (is a list of DOM based modules )
18352         Roo.each(this.elmodules, function(e) {
18353             mods.push(e);
18354             if (!this.topModule &&
18355                 typeof(e.parent) == 'string' &&
18356                 e.parent.substring(0,1) == '#' &&
18357                 Roo.get(e.parent.substr(1))
18358                ) {
18359                 
18360                 _this.topModule = e;
18361             }
18362             
18363         });
18364
18365         
18366         // add modules to their parents..
18367         var addMod = function(m) {
18368             Roo.debug && Roo.log("build Order: add: " + m.name);
18369                 
18370             mods.push(m);
18371             if (m.modules && !m.disabled) {
18372                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
18373                 m.modules.keySort('ASC',  cmp );
18374                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
18375     
18376                 m.modules.each(addMod);
18377             } else {
18378                 Roo.debug && Roo.log("build Order: no child modules");
18379             }
18380             // not sure if this is used any more..
18381             if (m.finalize) {
18382                 m.finalize.name = m.name + " (clean up) ";
18383                 mods.push(m.finalize);
18384             }
18385             
18386         }
18387         if (this.topModule && this.topModule.modules) { 
18388             this.topModule.modules.keySort('ASC',  cmp );
18389             this.topModule.modules.each(addMod);
18390         } 
18391         return mods;
18392     },
18393     
18394      /**
18395      * Build the registered modules.
18396      * @param {Object} parent element.
18397      * @param {Function} optional method to call after module has been added.
18398      * 
18399      */ 
18400    
18401     build : function(opts) 
18402     {
18403         
18404         if (typeof(opts) != 'undefined') {
18405             Roo.apply(this,opts);
18406         }
18407         
18408         this.preBuild();
18409         var mods = this.buildOrder();
18410       
18411         //this.allmods = mods;
18412         //Roo.debug && Roo.log(mods);
18413         //return;
18414         if (!mods.length) { // should not happen
18415             throw "NO modules!!!";
18416         }
18417         
18418         
18419         var msg = "Building Interface...";
18420         // flash it up as modal - so we store the mask!?
18421         if (!this.hideProgress && Roo.MessageBox) {
18422             Roo.MessageBox.show({ title: 'loading' });
18423             Roo.MessageBox.show({
18424                title: "Please wait...",
18425                msg: msg,
18426                width:450,
18427                progress:true,
18428                buttons : false,
18429                closable:false,
18430                modal: false
18431               
18432             });
18433         }
18434         var total = mods.length;
18435         
18436         var _this = this;
18437         var progressRun = function() {
18438             if (!mods.length) {
18439                 Roo.debug && Roo.log('hide?');
18440                 if (!this.hideProgress && Roo.MessageBox) {
18441                     Roo.MessageBox.hide();
18442                 }
18443                 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
18444                 
18445                 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
18446                 
18447                 // THE END...
18448                 return false;   
18449             }
18450             
18451             var m = mods.shift();
18452             
18453             
18454             Roo.debug && Roo.log(m);
18455             // not sure if this is supported any more.. - modules that are are just function
18456             if (typeof(m) == 'function') { 
18457                 m.call(this);
18458                 return progressRun.defer(10, _this);
18459             } 
18460             
18461             
18462             msg = "Building Interface " + (total  - mods.length) + 
18463                     " of " + total + 
18464                     (m.name ? (' - ' + m.name) : '');
18465                         Roo.debug && Roo.log(msg);
18466             if (!_this.hideProgress &&  Roo.MessageBox) { 
18467                 Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
18468             }
18469             
18470          
18471             // is the module disabled?
18472             var disabled = (typeof(m.disabled) == 'function') ?
18473                 m.disabled.call(m.module.disabled) : m.disabled;    
18474             
18475             
18476             if (disabled) {
18477                 return progressRun(); // we do not update the display!
18478             }
18479             
18480             // now build 
18481             
18482                         
18483                         
18484             m.render();
18485             // it's 10 on top level, and 1 on others??? why...
18486             return progressRun.defer(10, _this);
18487              
18488         }
18489         progressRun.defer(1, _this);
18490      
18491         
18492         
18493     },
18494     /**
18495      * Overlay a set of modified strings onto a component
18496      * This is dependant on our builder exporting the strings and 'named strings' elements.
18497      * 
18498      * @param {Object} element to overlay on - eg. Pman.Dialog.Login
18499      * @param {Object} associative array of 'named' string and it's new value.
18500      * 
18501      */
18502         overlayStrings : function( component, strings )
18503     {
18504         if (typeof(component['_named_strings']) == 'undefined') {
18505             throw "ERROR: component does not have _named_strings";
18506         }
18507         for ( var k in strings ) {
18508             var md = typeof(component['_named_strings'][k]) == 'undefined' ? false : component['_named_strings'][k];
18509             if (md !== false) {
18510                 component['_strings'][md] = strings[k];
18511             } else {
18512                 Roo.log('could not find named string: ' + k + ' in');
18513                 Roo.log(component);
18514             }
18515             
18516         }
18517         
18518     },
18519     
18520         
18521         /**
18522          * Event Object.
18523          *
18524          *
18525          */
18526         event: false, 
18527     /**
18528          * wrapper for event.on - aliased later..  
18529          * Typically use to register a event handler for register:
18530          *
18531          * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
18532          *
18533          */
18534     on : false
18535    
18536     
18537     
18538 });
18539
18540 Roo.XComponent.event = new Roo.util.Observable({
18541                 events : { 
18542                         /**
18543                          * @event register
18544                          * Fires when an Component is registered,
18545                          * set the disable property on the Component to stop registration.
18546                          * @param {Roo.XComponent} c the component being registerd.
18547                          * 
18548                          */
18549                         'register' : true,
18550             /**
18551                          * @event beforebuild
18552                          * Fires before each Component is built
18553                          * can be used to apply permissions.
18554                          * @param {Roo.XComponent} c the component being registerd.
18555                          * 
18556                          */
18557                         'beforebuild' : true,
18558                         /**
18559                          * @event buildcomplete
18560                          * Fires on the top level element when all elements have been built
18561                          * @param {Roo.XComponent} the top level component.
18562                          */
18563                         'buildcomplete' : true
18564                         
18565                 }
18566 });
18567
18568 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event); 
18569  //
18570  /**
18571  * marked - a markdown parser
18572  * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
18573  * https://github.com/chjj/marked
18574  */
18575
18576
18577 /**
18578  *
18579  * Roo.Markdown - is a very crude wrapper around marked..
18580  *
18581  * usage:
18582  * 
18583  * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
18584  * 
18585  * Note: move the sample code to the bottom of this
18586  * file before uncommenting it.
18587  *
18588  */
18589
18590 Roo.Markdown = {};
18591 Roo.Markdown.toHtml = function(text) {
18592     
18593     var c = new Roo.Markdown.marked.setOptions({
18594             renderer: new Roo.Markdown.marked.Renderer(),
18595             gfm: true,
18596             tables: true,
18597             breaks: false,
18598             pedantic: false,
18599             sanitize: false,
18600             smartLists: true,
18601             smartypants: false
18602           });
18603     // A FEW HACKS!!?
18604     
18605     text = text.replace(/\\\n/g,' ');
18606     return Roo.Markdown.marked(text);
18607 };
18608 //
18609 // converter
18610 //
18611 // Wraps all "globals" so that the only thing
18612 // exposed is makeHtml().
18613 //
18614 (function() {
18615     
18616      /**
18617          * eval:var:escape
18618          * eval:var:unescape
18619          * eval:var:replace
18620          */
18621       
18622     /**
18623      * Helpers
18624      */
18625     
18626     var escape = function (html, encode) {
18627       return html
18628         .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&amp;')
18629         .replace(/</g, '&lt;')
18630         .replace(/>/g, '&gt;')
18631         .replace(/"/g, '&quot;')
18632         .replace(/'/g, '&#39;');
18633     }
18634     
18635     var unescape = function (html) {
18636         // explicitly match decimal, hex, and named HTML entities 
18637       return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
18638         n = n.toLowerCase();
18639         if (n === 'colon') { return ':'; }
18640         if (n.charAt(0) === '#') {
18641           return n.charAt(1) === 'x'
18642             ? String.fromCharCode(parseInt(n.substring(2), 16))
18643             : String.fromCharCode(+n.substring(1));
18644         }
18645         return '';
18646       });
18647     }
18648     
18649     var replace = function (regex, opt) {
18650       regex = regex.source;
18651       opt = opt || '';
18652       return function self(name, val) {
18653         if (!name) { return new RegExp(regex, opt); }
18654         val = val.source || val;
18655         val = val.replace(/(^|[^\[])\^/g, '$1');
18656         regex = regex.replace(name, val);
18657         return self;
18658       };
18659     }
18660
18661
18662          /**
18663          * eval:var:noop
18664     */
18665     var noop = function () {}
18666     noop.exec = noop;
18667     
18668          /**
18669          * eval:var:merge
18670     */
18671     var merge = function (obj) {
18672       var i = 1
18673         , target
18674         , key;
18675     
18676       for (; i < arguments.length; i++) {
18677         target = arguments[i];
18678         for (key in target) {
18679           if (Object.prototype.hasOwnProperty.call(target, key)) {
18680             obj[key] = target[key];
18681           }
18682         }
18683       }
18684     
18685       return obj;
18686     }
18687     
18688     
18689     /**
18690      * Block-Level Grammar
18691      */
18692     
18693     
18694     
18695     
18696     var block = {
18697       newline: /^\n+/,
18698       code: /^( {4}[^\n]+\n*)+/,
18699       fences: noop,
18700       hr: /^( *[-*_]){3,} *(?:\n+|$)/,
18701       heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
18702       nptable: noop,
18703       lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
18704       blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
18705       list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
18706       html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
18707       def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
18708       table: noop,
18709       paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
18710       text: /^[^\n]+/
18711     };
18712     
18713     block.bullet = /(?:[*+-]|\d+\.)/;
18714     block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
18715     block.item = replace(block.item, 'gm')
18716       (/bull/g, block.bullet)
18717       ();
18718     
18719     block.list = replace(block.list)
18720       (/bull/g, block.bullet)
18721       ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
18722       ('def', '\\n+(?=' + block.def.source + ')')
18723       ();
18724     
18725     block.blockquote = replace(block.blockquote)
18726       ('def', block.def)
18727       ();
18728     
18729     block._tag = '(?!(?:'
18730       + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
18731       + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
18732       + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
18733     
18734     block.html = replace(block.html)
18735       ('comment', /<!--[\s\S]*?-->/)
18736       ('closed', /<(tag)[\s\S]+?<\/\1>/)
18737       ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
18738       (/tag/g, block._tag)
18739       ();
18740     
18741     block.paragraph = replace(block.paragraph)
18742       ('hr', block.hr)
18743       ('heading', block.heading)
18744       ('lheading', block.lheading)
18745       ('blockquote', block.blockquote)
18746       ('tag', '<' + block._tag)
18747       ('def', block.def)
18748       ();
18749     
18750     /**
18751      * Normal Block Grammar
18752      */
18753     
18754     block.normal = merge({}, block);
18755     
18756     /**
18757      * GFM Block Grammar
18758      */
18759     
18760     block.gfm = merge({}, block.normal, {
18761       fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
18762       paragraph: /^/,
18763       heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
18764     });
18765     
18766     block.gfm.paragraph = replace(block.paragraph)
18767       ('(?!', '(?!'
18768         + block.gfm.fences.source.replace('\\1', '\\2') + '|'
18769         + block.list.source.replace('\\1', '\\3') + '|')
18770       ();
18771     
18772     /**
18773      * GFM + Tables Block Grammar
18774      */
18775     
18776     block.tables = merge({}, block.gfm, {
18777       nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
18778       table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
18779     });
18780     
18781     /**
18782      * Block Lexer
18783      */
18784     
18785     var Lexer = function (options) {
18786       this.tokens = [];
18787       this.tokens.links = {};
18788       this.options = options || marked.defaults;
18789       this.rules = block.normal;
18790     
18791       if (this.options.gfm) {
18792         if (this.options.tables) {
18793           this.rules = block.tables;
18794         } else {
18795           this.rules = block.gfm;
18796         }
18797       }
18798     }
18799     
18800     /**
18801      * Expose Block Rules
18802      */
18803     
18804     Lexer.rules = block;
18805     
18806     /**
18807      * Static Lex Method
18808      */
18809     
18810     Lexer.lex = function(src, options) {
18811       var lexer = new Lexer(options);
18812       return lexer.lex(src);
18813     };
18814     
18815     /**
18816      * Preprocessing
18817      */
18818     
18819     Lexer.prototype.lex = function(src) {
18820       src = src
18821         .replace(/\r\n|\r/g, '\n')
18822         .replace(/\t/g, '    ')
18823         .replace(/\u00a0/g, ' ')
18824         .replace(/\u2424/g, '\n');
18825     
18826       return this.token(src, true);
18827     };
18828     
18829     /**
18830      * Lexing
18831      */
18832     
18833     Lexer.prototype.token = function(src, top, bq) {
18834       var src = src.replace(/^ +$/gm, '')
18835         , next
18836         , loose
18837         , cap
18838         , bull
18839         , b
18840         , item
18841         , space
18842         , i
18843         , l;
18844     
18845       while (src) {
18846         // newline
18847         if (cap = this.rules.newline.exec(src)) {
18848           src = src.substring(cap[0].length);
18849           if (cap[0].length > 1) {
18850             this.tokens.push({
18851               type: 'space'
18852             });
18853           }
18854         }
18855     
18856         // code
18857         if (cap = this.rules.code.exec(src)) {
18858           src = src.substring(cap[0].length);
18859           cap = cap[0].replace(/^ {4}/gm, '');
18860           this.tokens.push({
18861             type: 'code',
18862             text: !this.options.pedantic
18863               ? cap.replace(/\n+$/, '')
18864               : cap
18865           });
18866           continue;
18867         }
18868     
18869         // fences (gfm)
18870         if (cap = this.rules.fences.exec(src)) {
18871           src = src.substring(cap[0].length);
18872           this.tokens.push({
18873             type: 'code',
18874             lang: cap[2],
18875             text: cap[3] || ''
18876           });
18877           continue;
18878         }
18879     
18880         // heading
18881         if (cap = this.rules.heading.exec(src)) {
18882           src = src.substring(cap[0].length);
18883           this.tokens.push({
18884             type: 'heading',
18885             depth: cap[1].length,
18886             text: cap[2]
18887           });
18888           continue;
18889         }
18890     
18891         // table no leading pipe (gfm)
18892         if (top && (cap = this.rules.nptable.exec(src))) {
18893           src = src.substring(cap[0].length);
18894     
18895           item = {
18896             type: 'table',
18897             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
18898             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
18899             cells: cap[3].replace(/\n$/, '').split('\n')
18900           };
18901     
18902           for (i = 0; i < item.align.length; i++) {
18903             if (/^ *-+: *$/.test(item.align[i])) {
18904               item.align[i] = 'right';
18905             } else if (/^ *:-+: *$/.test(item.align[i])) {
18906               item.align[i] = 'center';
18907             } else if (/^ *:-+ *$/.test(item.align[i])) {
18908               item.align[i] = 'left';
18909             } else {
18910               item.align[i] = null;
18911             }
18912           }
18913     
18914           for (i = 0; i < item.cells.length; i++) {
18915             item.cells[i] = item.cells[i].split(/ *\| */);
18916           }
18917     
18918           this.tokens.push(item);
18919     
18920           continue;
18921         }
18922     
18923         // lheading
18924         if (cap = this.rules.lheading.exec(src)) {
18925           src = src.substring(cap[0].length);
18926           this.tokens.push({
18927             type: 'heading',
18928             depth: cap[2] === '=' ? 1 : 2,
18929             text: cap[1]
18930           });
18931           continue;
18932         }
18933     
18934         // hr
18935         if (cap = this.rules.hr.exec(src)) {
18936           src = src.substring(cap[0].length);
18937           this.tokens.push({
18938             type: 'hr'
18939           });
18940           continue;
18941         }
18942     
18943         // blockquote
18944         if (cap = this.rules.blockquote.exec(src)) {
18945           src = src.substring(cap[0].length);
18946     
18947           this.tokens.push({
18948             type: 'blockquote_start'
18949           });
18950     
18951           cap = cap[0].replace(/^ *> ?/gm, '');
18952     
18953           // Pass `top` to keep the current
18954           // "toplevel" state. This is exactly
18955           // how markdown.pl works.
18956           this.token(cap, top, true);
18957     
18958           this.tokens.push({
18959             type: 'blockquote_end'
18960           });
18961     
18962           continue;
18963         }
18964     
18965         // list
18966         if (cap = this.rules.list.exec(src)) {
18967           src = src.substring(cap[0].length);
18968           bull = cap[2];
18969     
18970           this.tokens.push({
18971             type: 'list_start',
18972             ordered: bull.length > 1
18973           });
18974     
18975           // Get each top-level item.
18976           cap = cap[0].match(this.rules.item);
18977     
18978           next = false;
18979           l = cap.length;
18980           i = 0;
18981     
18982           for (; i < l; i++) {
18983             item = cap[i];
18984     
18985             // Remove the list item's bullet
18986             // so it is seen as the next token.
18987             space = item.length;
18988             item = item.replace(/^ *([*+-]|\d+\.) +/, '');
18989     
18990             // Outdent whatever the
18991             // list item contains. Hacky.
18992             if (~item.indexOf('\n ')) {
18993               space -= item.length;
18994               item = !this.options.pedantic
18995                 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
18996                 : item.replace(/^ {1,4}/gm, '');
18997             }
18998     
18999             // Determine whether the next list item belongs here.
19000             // Backpedal if it does not belong in this list.
19001             if (this.options.smartLists && i !== l - 1) {
19002               b = block.bullet.exec(cap[i + 1])[0];
19003               if (bull !== b && !(bull.length > 1 && b.length > 1)) {
19004                 src = cap.slice(i + 1).join('\n') + src;
19005                 i = l - 1;
19006               }
19007             }
19008     
19009             // Determine whether item is loose or not.
19010             // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
19011             // for discount behavior.
19012             loose = next || /\n\n(?!\s*$)/.test(item);
19013             if (i !== l - 1) {
19014               next = item.charAt(item.length - 1) === '\n';
19015               if (!loose) { loose = next; }
19016             }
19017     
19018             this.tokens.push({
19019               type: loose
19020                 ? 'loose_item_start'
19021                 : 'list_item_start'
19022             });
19023     
19024             // Recurse.
19025             this.token(item, false, bq);
19026     
19027             this.tokens.push({
19028               type: 'list_item_end'
19029             });
19030           }
19031     
19032           this.tokens.push({
19033             type: 'list_end'
19034           });
19035     
19036           continue;
19037         }
19038     
19039         // html
19040         if (cap = this.rules.html.exec(src)) {
19041           src = src.substring(cap[0].length);
19042           this.tokens.push({
19043             type: this.options.sanitize
19044               ? 'paragraph'
19045               : 'html',
19046             pre: !this.options.sanitizer
19047               && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
19048             text: cap[0]
19049           });
19050           continue;
19051         }
19052     
19053         // def
19054         if ((!bq && top) && (cap = this.rules.def.exec(src))) {
19055           src = src.substring(cap[0].length);
19056           this.tokens.links[cap[1].toLowerCase()] = {
19057             href: cap[2],
19058             title: cap[3]
19059           };
19060           continue;
19061         }
19062     
19063         // table (gfm)
19064         if (top && (cap = this.rules.table.exec(src))) {
19065           src = src.substring(cap[0].length);
19066     
19067           item = {
19068             type: 'table',
19069             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
19070             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
19071             cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
19072           };
19073     
19074           for (i = 0; i < item.align.length; i++) {
19075             if (/^ *-+: *$/.test(item.align[i])) {
19076               item.align[i] = 'right';
19077             } else if (/^ *:-+: *$/.test(item.align[i])) {
19078               item.align[i] = 'center';
19079             } else if (/^ *:-+ *$/.test(item.align[i])) {
19080               item.align[i] = 'left';
19081             } else {
19082               item.align[i] = null;
19083             }
19084           }
19085     
19086           for (i = 0; i < item.cells.length; i++) {
19087             item.cells[i] = item.cells[i]
19088               .replace(/^ *\| *| *\| *$/g, '')
19089               .split(/ *\| */);
19090           }
19091     
19092           this.tokens.push(item);
19093     
19094           continue;
19095         }
19096     
19097         // top-level paragraph
19098         if (top && (cap = this.rules.paragraph.exec(src))) {
19099           src = src.substring(cap[0].length);
19100           this.tokens.push({
19101             type: 'paragraph',
19102             text: cap[1].charAt(cap[1].length - 1) === '\n'
19103               ? cap[1].slice(0, -1)
19104               : cap[1]
19105           });
19106           continue;
19107         }
19108     
19109         // text
19110         if (cap = this.rules.text.exec(src)) {
19111           // Top-level should never reach here.
19112           src = src.substring(cap[0].length);
19113           this.tokens.push({
19114             type: 'text',
19115             text: cap[0]
19116           });
19117           continue;
19118         }
19119     
19120         if (src) {
19121           throw new
19122             Error('Infinite loop on byte: ' + src.charCodeAt(0));
19123         }
19124       }
19125     
19126       return this.tokens;
19127     };
19128     
19129     /**
19130      * Inline-Level Grammar
19131      */
19132     
19133     var inline = {
19134       escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
19135       autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
19136       url: noop,
19137       tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
19138       link: /^!?\[(inside)\]\(href\)/,
19139       reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
19140       nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
19141       strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
19142       em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
19143       code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
19144       br: /^ {2,}\n(?!\s*$)/,
19145       del: noop,
19146       text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
19147     };
19148     
19149     inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
19150     inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
19151     
19152     inline.link = replace(inline.link)
19153       ('inside', inline._inside)
19154       ('href', inline._href)
19155       ();
19156     
19157     inline.reflink = replace(inline.reflink)
19158       ('inside', inline._inside)
19159       ();
19160     
19161     /**
19162      * Normal Inline Grammar
19163      */
19164     
19165     inline.normal = merge({}, inline);
19166     
19167     /**
19168      * Pedantic Inline Grammar
19169      */
19170     
19171     inline.pedantic = merge({}, inline.normal, {
19172       strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
19173       em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
19174     });
19175     
19176     /**
19177      * GFM Inline Grammar
19178      */
19179     
19180     inline.gfm = merge({}, inline.normal, {
19181       escape: replace(inline.escape)('])', '~|])')(),
19182       url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
19183       del: /^~~(?=\S)([\s\S]*?\S)~~/,
19184       text: replace(inline.text)
19185         (']|', '~]|')
19186         ('|', '|https?://|')
19187         ()
19188     });
19189     
19190     /**
19191      * GFM + Line Breaks Inline Grammar
19192      */
19193     
19194     inline.breaks = merge({}, inline.gfm, {
19195       br: replace(inline.br)('{2,}', '*')(),
19196       text: replace(inline.gfm.text)('{2,}', '*')()
19197     });
19198     
19199     /**
19200      * Inline Lexer & Compiler
19201      */
19202     
19203     var InlineLexer  = function (links, options) {
19204       this.options = options || marked.defaults;
19205       this.links = links;
19206       this.rules = inline.normal;
19207       this.renderer = this.options.renderer || new Renderer;
19208       this.renderer.options = this.options;
19209     
19210       if (!this.links) {
19211         throw new
19212           Error('Tokens array requires a `links` property.');
19213       }
19214     
19215       if (this.options.gfm) {
19216         if (this.options.breaks) {
19217           this.rules = inline.breaks;
19218         } else {
19219           this.rules = inline.gfm;
19220         }
19221       } else if (this.options.pedantic) {
19222         this.rules = inline.pedantic;
19223       }
19224     }
19225     
19226     /**
19227      * Expose Inline Rules
19228      */
19229     
19230     InlineLexer.rules = inline;
19231     
19232     /**
19233      * Static Lexing/Compiling Method
19234      */
19235     
19236     InlineLexer.output = function(src, links, options) {
19237       var inline = new InlineLexer(links, options);
19238       return inline.output(src);
19239     };
19240     
19241     /**
19242      * Lexing/Compiling
19243      */
19244     
19245     InlineLexer.prototype.output = function(src) {
19246       var out = ''
19247         , link
19248         , text
19249         , href
19250         , cap;
19251     
19252       while (src) {
19253         // escape
19254         if (cap = this.rules.escape.exec(src)) {
19255           src = src.substring(cap[0].length);
19256           out += cap[1];
19257           continue;
19258         }
19259     
19260         // autolink
19261         if (cap = this.rules.autolink.exec(src)) {
19262           src = src.substring(cap[0].length);
19263           if (cap[2] === '@') {
19264             text = cap[1].charAt(6) === ':'
19265               ? this.mangle(cap[1].substring(7))
19266               : this.mangle(cap[1]);
19267             href = this.mangle('mailto:') + text;
19268           } else {
19269             text = escape(cap[1]);
19270             href = text;
19271           }
19272           out += this.renderer.link(href, null, text);
19273           continue;
19274         }
19275     
19276         // url (gfm)
19277         if (!this.inLink && (cap = this.rules.url.exec(src))) {
19278           src = src.substring(cap[0].length);
19279           text = escape(cap[1]);
19280           href = text;
19281           out += this.renderer.link(href, null, text);
19282           continue;
19283         }
19284     
19285         // tag
19286         if (cap = this.rules.tag.exec(src)) {
19287           if (!this.inLink && /^<a /i.test(cap[0])) {
19288             this.inLink = true;
19289           } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
19290             this.inLink = false;
19291           }
19292           src = src.substring(cap[0].length);
19293           out += this.options.sanitize
19294             ? this.options.sanitizer
19295               ? this.options.sanitizer(cap[0])
19296               : escape(cap[0])
19297             : cap[0];
19298           continue;
19299         }
19300     
19301         // link
19302         if (cap = this.rules.link.exec(src)) {
19303           src = src.substring(cap[0].length);
19304           this.inLink = true;
19305           out += this.outputLink(cap, {
19306             href: cap[2],
19307             title: cap[3]
19308           });
19309           this.inLink = false;
19310           continue;
19311         }
19312     
19313         // reflink, nolink
19314         if ((cap = this.rules.reflink.exec(src))
19315             || (cap = this.rules.nolink.exec(src))) {
19316           src = src.substring(cap[0].length);
19317           link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
19318           link = this.links[link.toLowerCase()];
19319           if (!link || !link.href) {
19320             out += cap[0].charAt(0);
19321             src = cap[0].substring(1) + src;
19322             continue;
19323           }
19324           this.inLink = true;
19325           out += this.outputLink(cap, link);
19326           this.inLink = false;
19327           continue;
19328         }
19329     
19330         // strong
19331         if (cap = this.rules.strong.exec(src)) {
19332           src = src.substring(cap[0].length);
19333           out += this.renderer.strong(this.output(cap[2] || cap[1]));
19334           continue;
19335         }
19336     
19337         // em
19338         if (cap = this.rules.em.exec(src)) {
19339           src = src.substring(cap[0].length);
19340           out += this.renderer.em(this.output(cap[2] || cap[1]));
19341           continue;
19342         }
19343     
19344         // code
19345         if (cap = this.rules.code.exec(src)) {
19346           src = src.substring(cap[0].length);
19347           out += this.renderer.codespan(escape(cap[2], true));
19348           continue;
19349         }
19350     
19351         // br
19352         if (cap = this.rules.br.exec(src)) {
19353           src = src.substring(cap[0].length);
19354           out += this.renderer.br();
19355           continue;
19356         }
19357     
19358         // del (gfm)
19359         if (cap = this.rules.del.exec(src)) {
19360           src = src.substring(cap[0].length);
19361           out += this.renderer.del(this.output(cap[1]));
19362           continue;
19363         }
19364     
19365         // text
19366         if (cap = this.rules.text.exec(src)) {
19367           src = src.substring(cap[0].length);
19368           out += this.renderer.text(escape(this.smartypants(cap[0])));
19369           continue;
19370         }
19371     
19372         if (src) {
19373           throw new
19374             Error('Infinite loop on byte: ' + src.charCodeAt(0));
19375         }
19376       }
19377     
19378       return out;
19379     };
19380     
19381     /**
19382      * Compile Link
19383      */
19384     
19385     InlineLexer.prototype.outputLink = function(cap, link) {
19386       var href = escape(link.href)
19387         , title = link.title ? escape(link.title) : null;
19388     
19389       return cap[0].charAt(0) !== '!'
19390         ? this.renderer.link(href, title, this.output(cap[1]))
19391         : this.renderer.image(href, title, escape(cap[1]));
19392     };
19393     
19394     /**
19395      * Smartypants Transformations
19396      */
19397     
19398     InlineLexer.prototype.smartypants = function(text) {
19399       if (!this.options.smartypants)  { return text; }
19400       return text
19401         // em-dashes
19402         .replace(/---/g, '\u2014')
19403         // en-dashes
19404         .replace(/--/g, '\u2013')
19405         // opening singles
19406         .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
19407         // closing singles & apostrophes
19408         .replace(/'/g, '\u2019')
19409         // opening doubles
19410         .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
19411         // closing doubles
19412         .replace(/"/g, '\u201d')
19413         // ellipses
19414         .replace(/\.{3}/g, '\u2026');
19415     };
19416     
19417     /**
19418      * Mangle Links
19419      */
19420     
19421     InlineLexer.prototype.mangle = function(text) {
19422       if (!this.options.mangle) { return text; }
19423       var out = ''
19424         , l = text.length
19425         , i = 0
19426         , ch;
19427     
19428       for (; i < l; i++) {
19429         ch = text.charCodeAt(i);
19430         if (Math.random() > 0.5) {
19431           ch = 'x' + ch.toString(16);
19432         }
19433         out += '&#' + ch + ';';
19434       }
19435     
19436       return out;
19437     };
19438     
19439     /**
19440      * Renderer
19441      */
19442     
19443      /**
19444          * eval:var:Renderer
19445     */
19446     
19447     var Renderer   = function (options) {
19448       this.options = options || {};
19449     }
19450     
19451     Renderer.prototype.code = function(code, lang, escaped) {
19452       if (this.options.highlight) {
19453         var out = this.options.highlight(code, lang);
19454         if (out != null && out !== code) {
19455           escaped = true;
19456           code = out;
19457         }
19458       } else {
19459             // hack!!! - it's already escapeD?
19460             escaped = true;
19461       }
19462     
19463       if (!lang) {
19464         return '<pre><code>'
19465           + (escaped ? code : escape(code, true))
19466           + '\n</code></pre>';
19467       }
19468     
19469       return '<pre><code class="'
19470         + this.options.langPrefix
19471         + escape(lang, true)
19472         + '">'
19473         + (escaped ? code : escape(code, true))
19474         + '\n</code></pre>\n';
19475     };
19476     
19477     Renderer.prototype.blockquote = function(quote) {
19478       return '<blockquote>\n' + quote + '</blockquote>\n';
19479     };
19480     
19481     Renderer.prototype.html = function(html) {
19482       return html;
19483     };
19484     
19485     Renderer.prototype.heading = function(text, level, raw) {
19486       return '<h'
19487         + level
19488         + ' id="'
19489         + this.options.headerPrefix
19490         + raw.toLowerCase().replace(/[^\w]+/g, '-')
19491         + '">'
19492         + text
19493         + '</h'
19494         + level
19495         + '>\n';
19496     };
19497     
19498     Renderer.prototype.hr = function() {
19499       return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
19500     };
19501     
19502     Renderer.prototype.list = function(body, ordered) {
19503       var type = ordered ? 'ol' : 'ul';
19504       return '<' + type + '>\n' + body + '</' + type + '>\n';
19505     };
19506     
19507     Renderer.prototype.listitem = function(text) {
19508       return '<li>' + text + '</li>\n';
19509     };
19510     
19511     Renderer.prototype.paragraph = function(text) {
19512       return '<p>' + text + '</p>\n';
19513     };
19514     
19515     Renderer.prototype.table = function(header, body) {
19516       return '<table class="table table-striped">\n'
19517         + '<thead>\n'
19518         + header
19519         + '</thead>\n'
19520         + '<tbody>\n'
19521         + body
19522         + '</tbody>\n'
19523         + '</table>\n';
19524     };
19525     
19526     Renderer.prototype.tablerow = function(content) {
19527       return '<tr>\n' + content + '</tr>\n';
19528     };
19529     
19530     Renderer.prototype.tablecell = function(content, flags) {
19531       var type = flags.header ? 'th' : 'td';
19532       var tag = flags.align
19533         ? '<' + type + ' style="text-align:' + flags.align + '">'
19534         : '<' + type + '>';
19535       return tag + content + '</' + type + '>\n';
19536     };
19537     
19538     // span level renderer
19539     Renderer.prototype.strong = function(text) {
19540       return '<strong>' + text + '</strong>';
19541     };
19542     
19543     Renderer.prototype.em = function(text) {
19544       return '<em>' + text + '</em>';
19545     };
19546     
19547     Renderer.prototype.codespan = function(text) {
19548       return '<code>' + text + '</code>';
19549     };
19550     
19551     Renderer.prototype.br = function() {
19552       return this.options.xhtml ? '<br/>' : '<br>';
19553     };
19554     
19555     Renderer.prototype.del = function(text) {
19556       return '<del>' + text + '</del>';
19557     };
19558     
19559     Renderer.prototype.link = function(href, title, text) {
19560       if (this.options.sanitize) {
19561         try {
19562           var prot = decodeURIComponent(unescape(href))
19563             .replace(/[^\w:]/g, '')
19564             .toLowerCase();
19565         } catch (e) {
19566           return '';
19567         }
19568         if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
19569           return '';
19570         }
19571       }
19572       var out = '<a href="' + href + '"';
19573       if (title) {
19574         out += ' title="' + title + '"';
19575       }
19576       out += '>' + text + '</a>';
19577       return out;
19578     };
19579     
19580     Renderer.prototype.image = function(href, title, text) {
19581       var out = '<img src="' + href + '" alt="' + text + '"';
19582       if (title) {
19583         out += ' title="' + title + '"';
19584       }
19585       out += this.options.xhtml ? '/>' : '>';
19586       return out;
19587     };
19588     
19589     Renderer.prototype.text = function(text) {
19590       return text;
19591     };
19592     
19593     /**
19594      * Parsing & Compiling
19595      */
19596          /**
19597          * eval:var:Parser
19598     */
19599     
19600     var Parser= function (options) {
19601       this.tokens = [];
19602       this.token = null;
19603       this.options = options || marked.defaults;
19604       this.options.renderer = this.options.renderer || new Renderer;
19605       this.renderer = this.options.renderer;
19606       this.renderer.options = this.options;
19607     }
19608     
19609     /**
19610      * Static Parse Method
19611      */
19612     
19613     Parser.parse = function(src, options, renderer) {
19614       var parser = new Parser(options, renderer);
19615       return parser.parse(src);
19616     };
19617     
19618     /**
19619      * Parse Loop
19620      */
19621     
19622     Parser.prototype.parse = function(src) {
19623       this.inline = new InlineLexer(src.links, this.options, this.renderer);
19624       this.tokens = src.reverse();
19625     
19626       var out = '';
19627       while (this.next()) {
19628         out += this.tok();
19629       }
19630     
19631       return out;
19632     };
19633     
19634     /**
19635      * Next Token
19636      */
19637     
19638     Parser.prototype.next = function() {
19639       return this.token = this.tokens.pop();
19640     };
19641     
19642     /**
19643      * Preview Next Token
19644      */
19645     
19646     Parser.prototype.peek = function() {
19647       return this.tokens[this.tokens.length - 1] || 0;
19648     };
19649     
19650     /**
19651      * Parse Text Tokens
19652      */
19653     
19654     Parser.prototype.parseText = function() {
19655       var body = this.token.text;
19656     
19657       while (this.peek().type === 'text') {
19658         body += '\n' + this.next().text;
19659       }
19660     
19661       return this.inline.output(body);
19662     };
19663     
19664     /**
19665      * Parse Current Token
19666      */
19667     
19668     Parser.prototype.tok = function() {
19669       switch (this.token.type) {
19670         case 'space': {
19671           return '';
19672         }
19673         case 'hr': {
19674           return this.renderer.hr();
19675         }
19676         case 'heading': {
19677           return this.renderer.heading(
19678             this.inline.output(this.token.text),
19679             this.token.depth,
19680             this.token.text);
19681         }
19682         case 'code': {
19683           return this.renderer.code(this.token.text,
19684             this.token.lang,
19685             this.token.escaped);
19686         }
19687         case 'table': {
19688           var header = ''
19689             , body = ''
19690             , i
19691             , row
19692             , cell
19693             , flags
19694             , j;
19695     
19696           // header
19697           cell = '';
19698           for (i = 0; i < this.token.header.length; i++) {
19699             flags = { header: true, align: this.token.align[i] };
19700             cell += this.renderer.tablecell(
19701               this.inline.output(this.token.header[i]),
19702               { header: true, align: this.token.align[i] }
19703             );
19704           }
19705           header += this.renderer.tablerow(cell);
19706     
19707           for (i = 0; i < this.token.cells.length; i++) {
19708             row = this.token.cells[i];
19709     
19710             cell = '';
19711             for (j = 0; j < row.length; j++) {
19712               cell += this.renderer.tablecell(
19713                 this.inline.output(row[j]),
19714                 { header: false, align: this.token.align[j] }
19715               );
19716             }
19717     
19718             body += this.renderer.tablerow(cell);
19719           }
19720           return this.renderer.table(header, body);
19721         }
19722         case 'blockquote_start': {
19723           var body = '';
19724     
19725           while (this.next().type !== 'blockquote_end') {
19726             body += this.tok();
19727           }
19728     
19729           return this.renderer.blockquote(body);
19730         }
19731         case 'list_start': {
19732           var body = ''
19733             , ordered = this.token.ordered;
19734     
19735           while (this.next().type !== 'list_end') {
19736             body += this.tok();
19737           }
19738     
19739           return this.renderer.list(body, ordered);
19740         }
19741         case 'list_item_start': {
19742           var body = '';
19743     
19744           while (this.next().type !== 'list_item_end') {
19745             body += this.token.type === 'text'
19746               ? this.parseText()
19747               : this.tok();
19748           }
19749     
19750           return this.renderer.listitem(body);
19751         }
19752         case 'loose_item_start': {
19753           var body = '';
19754     
19755           while (this.next().type !== 'list_item_end') {
19756             body += this.tok();
19757           }
19758     
19759           return this.renderer.listitem(body);
19760         }
19761         case 'html': {
19762           var html = !this.token.pre && !this.options.pedantic
19763             ? this.inline.output(this.token.text)
19764             : this.token.text;
19765           return this.renderer.html(html);
19766         }
19767         case 'paragraph': {
19768           return this.renderer.paragraph(this.inline.output(this.token.text));
19769         }
19770         case 'text': {
19771           return this.renderer.paragraph(this.parseText());
19772         }
19773       }
19774     };
19775   
19776     
19777     /**
19778      * Marked
19779      */
19780          /**
19781          * eval:var:marked
19782     */
19783     var marked = function (src, opt, callback) {
19784       if (callback || typeof opt === 'function') {
19785         if (!callback) {
19786           callback = opt;
19787           opt = null;
19788         }
19789     
19790         opt = merge({}, marked.defaults, opt || {});
19791     
19792         var highlight = opt.highlight
19793           , tokens
19794           , pending
19795           , i = 0;
19796     
19797         try {
19798           tokens = Lexer.lex(src, opt)
19799         } catch (e) {
19800           return callback(e);
19801         }
19802     
19803         pending = tokens.length;
19804          /**
19805          * eval:var:done
19806     */
19807         var done = function(err) {
19808           if (err) {
19809             opt.highlight = highlight;
19810             return callback(err);
19811           }
19812     
19813           var out;
19814     
19815           try {
19816             out = Parser.parse(tokens, opt);
19817           } catch (e) {
19818             err = e;
19819           }
19820     
19821           opt.highlight = highlight;
19822     
19823           return err
19824             ? callback(err)
19825             : callback(null, out);
19826         };
19827     
19828         if (!highlight || highlight.length < 3) {
19829           return done();
19830         }
19831     
19832         delete opt.highlight;
19833     
19834         if (!pending) { return done(); }
19835     
19836         for (; i < tokens.length; i++) {
19837           (function(token) {
19838             if (token.type !== 'code') {
19839               return --pending || done();
19840             }
19841             return highlight(token.text, token.lang, function(err, code) {
19842               if (err) { return done(err); }
19843               if (code == null || code === token.text) {
19844                 return --pending || done();
19845               }
19846               token.text = code;
19847               token.escaped = true;
19848               --pending || done();
19849             });
19850           })(tokens[i]);
19851         }
19852     
19853         return;
19854       }
19855       try {
19856         if (opt) { opt = merge({}, marked.defaults, opt); }
19857         return Parser.parse(Lexer.lex(src, opt), opt);
19858       } catch (e) {
19859         e.message += '\nPlease report this to https://github.com/chjj/marked.';
19860         if ((opt || marked.defaults).silent) {
19861           return '<p>An error occured:</p><pre>'
19862             + escape(e.message + '', true)
19863             + '</pre>';
19864         }
19865         throw e;
19866       }
19867     }
19868     
19869     /**
19870      * Options
19871      */
19872     
19873     marked.options =
19874     marked.setOptions = function(opt) {
19875       merge(marked.defaults, opt);
19876       return marked;
19877     };
19878     
19879     marked.defaults = {
19880       gfm: true,
19881       tables: true,
19882       breaks: false,
19883       pedantic: false,
19884       sanitize: false,
19885       sanitizer: null,
19886       mangle: true,
19887       smartLists: false,
19888       silent: false,
19889       highlight: null,
19890       langPrefix: 'lang-',
19891       smartypants: false,
19892       headerPrefix: '',
19893       renderer: new Renderer,
19894       xhtml: false
19895     };
19896     
19897     /**
19898      * Expose
19899      */
19900     
19901     marked.Parser = Parser;
19902     marked.parser = Parser.parse;
19903     
19904     marked.Renderer = Renderer;
19905     
19906     marked.Lexer = Lexer;
19907     marked.lexer = Lexer.lex;
19908     
19909     marked.InlineLexer = InlineLexer;
19910     marked.inlineLexer = InlineLexer.output;
19911     
19912     marked.parse = marked;
19913     
19914     Roo.Markdown.marked = marked;
19915
19916 })();/*
19917  * Based on:
19918  * Ext JS Library 1.1.1
19919  * Copyright(c) 2006-2007, Ext JS, LLC.
19920  *
19921  * Originally Released Under LGPL - original licence link has changed is not relivant.
19922  *
19923  * Fork - LGPL
19924  * <script type="text/javascript">
19925  */
19926
19927
19928
19929 /*
19930  * These classes are derivatives of the similarly named classes in the YUI Library.
19931  * The original license:
19932  * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
19933  * Code licensed under the BSD License:
19934  * http://developer.yahoo.net/yui/license.txt
19935  */
19936
19937 (function() {
19938
19939 var Event=Roo.EventManager;
19940 var Dom=Roo.lib.Dom;
19941
19942 /**
19943  * @class Roo.dd.DragDrop
19944  * @extends Roo.util.Observable
19945  * Defines the interface and base operation of items that that can be
19946  * dragged or can be drop targets.  It was designed to be extended, overriding
19947  * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
19948  * Up to three html elements can be associated with a DragDrop instance:
19949  * <ul>
19950  * <li>linked element: the element that is passed into the constructor.
19951  * This is the element which defines the boundaries for interaction with
19952  * other DragDrop objects.</li>
19953  * <li>handle element(s): The drag operation only occurs if the element that
19954  * was clicked matches a handle element.  By default this is the linked
19955  * element, but there are times that you will want only a portion of the
19956  * linked element to initiate the drag operation, and the setHandleElId()
19957  * method provides a way to define this.</li>
19958  * <li>drag element: this represents the element that would be moved along
19959  * with the cursor during a drag operation.  By default, this is the linked
19960  * element itself as in {@link Roo.dd.DD}.  setDragElId() lets you define
19961  * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
19962  * </li>
19963  * </ul>
19964  * This class should not be instantiated until the onload event to ensure that
19965  * the associated elements are available.
19966  * The following would define a DragDrop obj that would interact with any
19967  * other DragDrop obj in the "group1" group:
19968  * <pre>
19969  *  dd = new Roo.dd.DragDrop("div1", "group1");
19970  * </pre>
19971  * Since none of the event handlers have been implemented, nothing would
19972  * actually happen if you were to run the code above.  Normally you would
19973  * override this class or one of the default implementations, but you can
19974  * also override the methods you want on an instance of the class...
19975  * <pre>
19976  *  dd.onDragDrop = function(e, id) {
19977  *  &nbsp;&nbsp;alert("dd was dropped on " + id);
19978  *  }
19979  * </pre>
19980  * @constructor
19981  * @param {String} id of the element that is linked to this instance
19982  * @param {String} sGroup the group of related DragDrop objects
19983  * @param {object} config an object containing configurable attributes
19984  *                Valid properties for DragDrop:
19985  *                    padding, isTarget, maintainOffset, primaryButtonOnly
19986  */
19987 Roo.dd.DragDrop = function(id, sGroup, config) {
19988     if (id) {
19989         this.init(id, sGroup, config);
19990     }
19991     
19992 };
19993
19994 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
19995
19996     /**
19997      * The id of the element associated with this object.  This is what we
19998      * refer to as the "linked element" because the size and position of
19999      * this element is used to determine when the drag and drop objects have
20000      * interacted.
20001      * @property id
20002      * @type String
20003      */
20004     id: null,
20005
20006     /**
20007      * Configuration attributes passed into the constructor
20008      * @property config
20009      * @type object
20010      */
20011     config: null,
20012
20013     /**
20014      * The id of the element that will be dragged.  By default this is same
20015      * as the linked element , but could be changed to another element. Ex:
20016      * Roo.dd.DDProxy
20017      * @property dragElId
20018      * @type String
20019      * @private
20020      */
20021     dragElId: null,
20022
20023     /**
20024      * the id of the element that initiates the drag operation.  By default
20025      * this is the linked element, but could be changed to be a child of this
20026      * element.  This lets us do things like only starting the drag when the
20027      * header element within the linked html element is clicked.
20028      * @property handleElId
20029      * @type String
20030      * @private
20031      */
20032     handleElId: null,
20033
20034     /**
20035      * An associative array of HTML tags that will be ignored if clicked.
20036      * @property invalidHandleTypes
20037      * @type {string: string}
20038      */
20039     invalidHandleTypes: null,
20040
20041     /**
20042      * An associative array of ids for elements that will be ignored if clicked
20043      * @property invalidHandleIds
20044      * @type {string: string}
20045      */
20046     invalidHandleIds: null,
20047
20048     /**
20049      * An indexted array of css class names for elements that will be ignored
20050      * if clicked.
20051      * @property invalidHandleClasses
20052      * @type string[]
20053      */
20054     invalidHandleClasses: null,
20055
20056     /**
20057      * The linked element's absolute X position at the time the drag was
20058      * started
20059      * @property startPageX
20060      * @type int
20061      * @private
20062      */
20063     startPageX: 0,
20064
20065     /**
20066      * The linked element's absolute X position at the time the drag was
20067      * started
20068      * @property startPageY
20069      * @type int
20070      * @private
20071      */
20072     startPageY: 0,
20073
20074     /**
20075      * The group defines a logical collection of DragDrop objects that are
20076      * related.  Instances only get events when interacting with other
20077      * DragDrop object in the same group.  This lets us define multiple
20078      * groups using a single DragDrop subclass if we want.
20079      * @property groups
20080      * @type {string: string}
20081      */
20082     groups: null,
20083
20084     /**
20085      * Individual drag/drop instances can be locked.  This will prevent
20086      * onmousedown start drag.
20087      * @property locked
20088      * @type boolean
20089      * @private
20090      */
20091     locked: false,
20092
20093     /**
20094      * Lock this instance
20095      * @method lock
20096      */
20097     lock: function() { this.locked = true; },
20098
20099     /**
20100      * Unlock this instace
20101      * @method unlock
20102      */
20103     unlock: function() { this.locked = false; },
20104
20105     /**
20106      * By default, all insances can be a drop target.  This can be disabled by
20107      * setting isTarget to false.
20108      * @method isTarget
20109      * @type boolean
20110      */
20111     isTarget: true,
20112
20113     /**
20114      * The padding configured for this drag and drop object for calculating
20115      * the drop zone intersection with this object.
20116      * @method padding
20117      * @type int[]
20118      */
20119     padding: null,
20120
20121     /**
20122      * Cached reference to the linked element
20123      * @property _domRef
20124      * @private
20125      */
20126     _domRef: null,
20127
20128     /**
20129      * Internal typeof flag
20130      * @property __ygDragDrop
20131      * @private
20132      */
20133     __ygDragDrop: true,
20134
20135     /**
20136      * Set to true when horizontal contraints are applied
20137      * @property constrainX
20138      * @type boolean
20139      * @private
20140      */
20141     constrainX: false,
20142
20143     /**
20144      * Set to true when vertical contraints are applied
20145      * @property constrainY
20146      * @type boolean
20147      * @private
20148      */
20149     constrainY: false,
20150
20151     /**
20152      * The left constraint
20153      * @property minX
20154      * @type int
20155      * @private
20156      */
20157     minX: 0,
20158
20159     /**
20160      * The right constraint
20161      * @property maxX
20162      * @type int
20163      * @private
20164      */
20165     maxX: 0,
20166
20167     /**
20168      * The up constraint
20169      * @property minY
20170      * @type int
20171      * @type int
20172      * @private
20173      */
20174     minY: 0,
20175
20176     /**
20177      * The down constraint
20178      * @property maxY
20179      * @type int
20180      * @private
20181      */
20182     maxY: 0,
20183
20184     /**
20185      * Maintain offsets when we resetconstraints.  Set to true when you want
20186      * the position of the element relative to its parent to stay the same
20187      * when the page changes
20188      *
20189      * @property maintainOffset
20190      * @type boolean
20191      */
20192     maintainOffset: false,
20193
20194     /**
20195      * Array of pixel locations the element will snap to if we specified a
20196      * horizontal graduation/interval.  This array is generated automatically
20197      * when you define a tick interval.
20198      * @property xTicks
20199      * @type int[]
20200      */
20201     xTicks: null,
20202
20203     /**
20204      * Array of pixel locations the element will snap to if we specified a
20205      * vertical graduation/interval.  This array is generated automatically
20206      * when you define a tick interval.
20207      * @property yTicks
20208      * @type int[]
20209      */
20210     yTicks: null,
20211
20212     /**
20213      * By default the drag and drop instance will only respond to the primary
20214      * button click (left button for a right-handed mouse).  Set to true to
20215      * allow drag and drop to start with any mouse click that is propogated
20216      * by the browser
20217      * @property primaryButtonOnly
20218      * @type boolean
20219      */
20220     primaryButtonOnly: true,
20221
20222     /**
20223      * The availabe property is false until the linked dom element is accessible.
20224      * @property available
20225      * @type boolean
20226      */
20227     available: false,
20228
20229     /**
20230      * By default, drags can only be initiated if the mousedown occurs in the
20231      * region the linked element is.  This is done in part to work around a
20232      * bug in some browsers that mis-report the mousedown if the previous
20233      * mouseup happened outside of the window.  This property is set to true
20234      * if outer handles are defined.
20235      *
20236      * @property hasOuterHandles
20237      * @type boolean
20238      * @default false
20239      */
20240     hasOuterHandles: false,
20241
20242     /**
20243      * Code that executes immediately before the startDrag event
20244      * @method b4StartDrag
20245      * @private
20246      */
20247     b4StartDrag: function(x, y) { },
20248
20249     /**
20250      * Abstract method called after a drag/drop object is clicked
20251      * and the drag or mousedown time thresholds have beeen met.
20252      * @method startDrag
20253      * @param {int} X click location
20254      * @param {int} Y click location
20255      */
20256     startDrag: function(x, y) { /* override this */ },
20257
20258     /**
20259      * Code that executes immediately before the onDrag event
20260      * @method b4Drag
20261      * @private
20262      */
20263     b4Drag: function(e) { },
20264
20265     /**
20266      * Abstract method called during the onMouseMove event while dragging an
20267      * object.
20268      * @method onDrag
20269      * @param {Event} e the mousemove event
20270      */
20271     onDrag: function(e) { /* override this */ },
20272
20273     /**
20274      * Abstract method called when this element fist begins hovering over
20275      * another DragDrop obj
20276      * @method onDragEnter
20277      * @param {Event} e the mousemove event
20278      * @param {String|DragDrop[]} id In POINT mode, the element
20279      * id this is hovering over.  In INTERSECT mode, an array of one or more
20280      * dragdrop items being hovered over.
20281      */
20282     onDragEnter: function(e, id) { /* override this */ },
20283
20284     /**
20285      * Code that executes immediately before the onDragOver event
20286      * @method b4DragOver
20287      * @private
20288      */
20289     b4DragOver: function(e) { },
20290
20291     /**
20292      * Abstract method called when this element is hovering over another
20293      * DragDrop obj
20294      * @method onDragOver
20295      * @param {Event} e the mousemove event
20296      * @param {String|DragDrop[]} id In POINT mode, the element
20297      * id this is hovering over.  In INTERSECT mode, an array of dd items
20298      * being hovered over.
20299      */
20300     onDragOver: function(e, id) { /* override this */ },
20301
20302     /**
20303      * Code that executes immediately before the onDragOut event
20304      * @method b4DragOut
20305      * @private
20306      */
20307     b4DragOut: function(e) { },
20308
20309     /**
20310      * Abstract method called when we are no longer hovering over an element
20311      * @method onDragOut
20312      * @param {Event} e the mousemove event
20313      * @param {String|DragDrop[]} id In POINT mode, the element
20314      * id this was hovering over.  In INTERSECT mode, an array of dd items
20315      * that the mouse is no longer over.
20316      */
20317     onDragOut: function(e, id) { /* override this */ },
20318
20319     /**
20320      * Code that executes immediately before the onDragDrop event
20321      * @method b4DragDrop
20322      * @private
20323      */
20324     b4DragDrop: function(e) { },
20325
20326     /**
20327      * Abstract method called when this item is dropped on another DragDrop
20328      * obj
20329      * @method onDragDrop
20330      * @param {Event} e the mouseup event
20331      * @param {String|DragDrop[]} id In POINT mode, the element
20332      * id this was dropped on.  In INTERSECT mode, an array of dd items this
20333      * was dropped on.
20334      */
20335     onDragDrop: function(e, id) { /* override this */ },
20336
20337     /**
20338      * Abstract method called when this item is dropped on an area with no
20339      * drop target
20340      * @method onInvalidDrop
20341      * @param {Event} e the mouseup event
20342      */
20343     onInvalidDrop: function(e) { /* override this */ },
20344
20345     /**
20346      * Code that executes immediately before the endDrag event
20347      * @method b4EndDrag
20348      * @private
20349      */
20350     b4EndDrag: function(e) { },
20351
20352     /**
20353      * Fired when we are done dragging the object
20354      * @method endDrag
20355      * @param {Event} e the mouseup event
20356      */
20357     endDrag: function(e) { /* override this */ },
20358
20359     /**
20360      * Code executed immediately before the onMouseDown event
20361      * @method b4MouseDown
20362      * @param {Event} e the mousedown event
20363      * @private
20364      */
20365     b4MouseDown: function(e) {  },
20366
20367     /**
20368      * Event handler that fires when a drag/drop obj gets a mousedown
20369      * @method onMouseDown
20370      * @param {Event} e the mousedown event
20371      */
20372     onMouseDown: function(e) { /* override this */ },
20373
20374     /**
20375      * Event handler that fires when a drag/drop obj gets a mouseup
20376      * @method onMouseUp
20377      * @param {Event} e the mouseup event
20378      */
20379     onMouseUp: function(e) { /* override this */ },
20380
20381     /**
20382      * Override the onAvailable method to do what is needed after the initial
20383      * position was determined.
20384      * @method onAvailable
20385      */
20386     onAvailable: function () {
20387     },
20388
20389     /*
20390      * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
20391      * @type Object
20392      */
20393     defaultPadding : {left:0, right:0, top:0, bottom:0},
20394
20395     /*
20396      * Initializes the drag drop object's constraints to restrict movement to a certain element.
20397  *
20398  * Usage:
20399  <pre><code>
20400  var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
20401                 { dragElId: "existingProxyDiv" });
20402  dd.startDrag = function(){
20403      this.constrainTo("parent-id");
20404  };
20405  </code></pre>
20406  * Or you can initalize it using the {@link Roo.Element} object:
20407  <pre><code>
20408  Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
20409      startDrag : function(){
20410          this.constrainTo("parent-id");
20411      }
20412  });
20413  </code></pre>
20414      * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
20415      * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
20416      * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
20417      * an object containing the sides to pad. For example: {right:10, bottom:10}
20418      * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
20419      */
20420     constrainTo : function(constrainTo, pad, inContent){
20421         if(typeof pad == "number"){
20422             pad = {left: pad, right:pad, top:pad, bottom:pad};
20423         }
20424         pad = pad || this.defaultPadding;
20425         var b = Roo.get(this.getEl()).getBox();
20426         var ce = Roo.get(constrainTo);
20427         var s = ce.getScroll();
20428         var c, cd = ce.dom;
20429         if(cd == document.body){
20430             c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
20431         }else{
20432             xy = ce.getXY();
20433             c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
20434         }
20435
20436
20437         var topSpace = b.y - c.y;
20438         var leftSpace = b.x - c.x;
20439
20440         this.resetConstraints();
20441         this.setXConstraint(leftSpace - (pad.left||0), // left
20442                 c.width - leftSpace - b.width - (pad.right||0) //right
20443         );
20444         this.setYConstraint(topSpace - (pad.top||0), //top
20445                 c.height - topSpace - b.height - (pad.bottom||0) //bottom
20446         );
20447     },
20448
20449     /**
20450      * Returns a reference to the linked element
20451      * @method getEl
20452      * @return {HTMLElement} the html element
20453      */
20454     getEl: function() {
20455         if (!this._domRef) {
20456             this._domRef = Roo.getDom(this.id);
20457         }
20458
20459         return this._domRef;
20460     },
20461
20462     /**
20463      * Returns a reference to the actual element to drag.  By default this is
20464      * the same as the html element, but it can be assigned to another
20465      * element. An example of this can be found in Roo.dd.DDProxy
20466      * @method getDragEl
20467      * @return {HTMLElement} the html element
20468      */
20469     getDragEl: function() {
20470         return Roo.getDom(this.dragElId);
20471     },
20472
20473     /**
20474      * Sets up the DragDrop object.  Must be called in the constructor of any
20475      * Roo.dd.DragDrop subclass
20476      * @method init
20477      * @param id the id of the linked element
20478      * @param {String} sGroup the group of related items
20479      * @param {object} config configuration attributes
20480      */
20481     init: function(id, sGroup, config) {
20482         this.initTarget(id, sGroup, config);
20483         if (!Roo.isTouch) {
20484             Event.on(this.id, "mousedown", this.handleMouseDown, this);
20485         }
20486         Event.on(this.id, "touchstart", this.handleMouseDown, this);
20487         // Event.on(this.id, "selectstart", Event.preventDefault);
20488     },
20489
20490     /**
20491      * Initializes Targeting functionality only... the object does not
20492      * get a mousedown handler.
20493      * @method initTarget
20494      * @param id the id of the linked element
20495      * @param {String} sGroup the group of related items
20496      * @param {object} config configuration attributes
20497      */
20498     initTarget: function(id, sGroup, config) {
20499
20500         // configuration attributes
20501         this.config = config || {};
20502
20503         // create a local reference to the drag and drop manager
20504         this.DDM = Roo.dd.DDM;
20505         // initialize the groups array
20506         this.groups = {};
20507
20508         // assume that we have an element reference instead of an id if the
20509         // parameter is not a string
20510         if (typeof id !== "string") {
20511             id = Roo.id(id);
20512         }
20513
20514         // set the id
20515         this.id = id;
20516
20517         // add to an interaction group
20518         this.addToGroup((sGroup) ? sGroup : "default");
20519
20520         // We don't want to register this as the handle with the manager
20521         // so we just set the id rather than calling the setter.
20522         this.handleElId = id;
20523
20524         // the linked element is the element that gets dragged by default
20525         this.setDragElId(id);
20526
20527         // by default, clicked anchors will not start drag operations.
20528         this.invalidHandleTypes = { A: "A" };
20529         this.invalidHandleIds = {};
20530         this.invalidHandleClasses = [];
20531
20532         this.applyConfig();
20533
20534         this.handleOnAvailable();
20535     },
20536
20537     /**
20538      * Applies the configuration parameters that were passed into the constructor.
20539      * This is supposed to happen at each level through the inheritance chain.  So
20540      * a DDProxy implentation will execute apply config on DDProxy, DD, and
20541      * DragDrop in order to get all of the parameters that are available in
20542      * each object.
20543      * @method applyConfig
20544      */
20545     applyConfig: function() {
20546
20547         // configurable properties:
20548         //    padding, isTarget, maintainOffset, primaryButtonOnly
20549         this.padding           = this.config.padding || [0, 0, 0, 0];
20550         this.isTarget          = (this.config.isTarget !== false);
20551         this.maintainOffset    = (this.config.maintainOffset);
20552         this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
20553
20554     },
20555
20556     /**
20557      * Executed when the linked element is available
20558      * @method handleOnAvailable
20559      * @private
20560      */
20561     handleOnAvailable: function() {
20562         this.available = true;
20563         this.resetConstraints();
20564         this.onAvailable();
20565     },
20566
20567      /**
20568      * Configures the padding for the target zone in px.  Effectively expands
20569      * (or reduces) the virtual object size for targeting calculations.
20570      * Supports css-style shorthand; if only one parameter is passed, all sides
20571      * will have that padding, and if only two are passed, the top and bottom
20572      * will have the first param, the left and right the second.
20573      * @method setPadding
20574      * @param {int} iTop    Top pad
20575      * @param {int} iRight  Right pad
20576      * @param {int} iBot    Bot pad
20577      * @param {int} iLeft   Left pad
20578      */
20579     setPadding: function(iTop, iRight, iBot, iLeft) {
20580         // this.padding = [iLeft, iRight, iTop, iBot];
20581         if (!iRight && 0 !== iRight) {
20582             this.padding = [iTop, iTop, iTop, iTop];
20583         } else if (!iBot && 0 !== iBot) {
20584             this.padding = [iTop, iRight, iTop, iRight];
20585         } else {
20586             this.padding = [iTop, iRight, iBot, iLeft];
20587         }
20588     },
20589
20590     /**
20591      * Stores the initial placement of the linked element.
20592      * @method setInitialPosition
20593      * @param {int} diffX   the X offset, default 0
20594      * @param {int} diffY   the Y offset, default 0
20595      */
20596     setInitPosition: function(diffX, diffY) {
20597         var el = this.getEl();
20598
20599         if (!this.DDM.verifyEl(el)) {
20600             return;
20601         }
20602
20603         var dx = diffX || 0;
20604         var dy = diffY || 0;
20605
20606         var p = Dom.getXY( el );
20607
20608         this.initPageX = p[0] - dx;
20609         this.initPageY = p[1] - dy;
20610
20611         this.lastPageX = p[0];
20612         this.lastPageY = p[1];
20613
20614
20615         this.setStartPosition(p);
20616     },
20617
20618     /**
20619      * Sets the start position of the element.  This is set when the obj
20620      * is initialized, the reset when a drag is started.
20621      * @method setStartPosition
20622      * @param pos current position (from previous lookup)
20623      * @private
20624      */
20625     setStartPosition: function(pos) {
20626         var p = pos || Dom.getXY( this.getEl() );
20627         this.deltaSetXY = null;
20628
20629         this.startPageX = p[0];
20630         this.startPageY = p[1];
20631     },
20632
20633     /**
20634      * Add this instance to a group of related drag/drop objects.  All
20635      * instances belong to at least one group, and can belong to as many
20636      * groups as needed.
20637      * @method addToGroup
20638      * @param sGroup {string} the name of the group
20639      */
20640     addToGroup: function(sGroup) {
20641         this.groups[sGroup] = true;
20642         this.DDM.regDragDrop(this, sGroup);
20643     },
20644
20645     /**
20646      * Remove's this instance from the supplied interaction group
20647      * @method removeFromGroup
20648      * @param {string}  sGroup  The group to drop
20649      */
20650     removeFromGroup: function(sGroup) {
20651         if (this.groups[sGroup]) {
20652             delete this.groups[sGroup];
20653         }
20654
20655         this.DDM.removeDDFromGroup(this, sGroup);
20656     },
20657
20658     /**
20659      * Allows you to specify that an element other than the linked element
20660      * will be moved with the cursor during a drag
20661      * @method setDragElId
20662      * @param id {string} the id of the element that will be used to initiate the drag
20663      */
20664     setDragElId: function(id) {
20665         this.dragElId = id;
20666     },
20667
20668     /**
20669      * Allows you to specify a child of the linked element that should be
20670      * used to initiate the drag operation.  An example of this would be if
20671      * you have a content div with text and links.  Clicking anywhere in the
20672      * content area would normally start the drag operation.  Use this method
20673      * to specify that an element inside of the content div is the element
20674      * that starts the drag operation.
20675      * @method setHandleElId
20676      * @param id {string} the id of the element that will be used to
20677      * initiate the drag.
20678      */
20679     setHandleElId: function(id) {
20680         if (typeof id !== "string") {
20681             id = Roo.id(id);
20682         }
20683         this.handleElId = id;
20684         this.DDM.regHandle(this.id, id);
20685     },
20686
20687     /**
20688      * Allows you to set an element outside of the linked element as a drag
20689      * handle
20690      * @method setOuterHandleElId
20691      * @param id the id of the element that will be used to initiate the drag
20692      */
20693     setOuterHandleElId: function(id) {
20694         if (typeof id !== "string") {
20695             id = Roo.id(id);
20696         }
20697         Event.on(id, "mousedown",
20698                 this.handleMouseDown, this);
20699         this.setHandleElId(id);
20700
20701         this.hasOuterHandles = true;
20702     },
20703
20704     /**
20705      * Remove all drag and drop hooks for this element
20706      * @method unreg
20707      */
20708     unreg: function() {
20709         Event.un(this.id, "mousedown",
20710                 this.handleMouseDown);
20711         Event.un(this.id, "touchstart",
20712                 this.handleMouseDown);
20713         this._domRef = null;
20714         this.DDM._remove(this);
20715     },
20716
20717     destroy : function(){
20718         this.unreg();
20719     },
20720
20721     /**
20722      * Returns true if this instance is locked, or the drag drop mgr is locked
20723      * (meaning that all drag/drop is disabled on the page.)
20724      * @method isLocked
20725      * @return {boolean} true if this obj or all drag/drop is locked, else
20726      * false
20727      */
20728     isLocked: function() {
20729         return (this.DDM.isLocked() || this.locked);
20730     },
20731
20732     /**
20733      * Fired when this object is clicked
20734      * @method handleMouseDown
20735      * @param {Event} e
20736      * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
20737      * @private
20738      */
20739     handleMouseDown: function(e, oDD){
20740      
20741         if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
20742             //Roo.log('not touch/ button !=0');
20743             return;
20744         }
20745         if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
20746             return; // double touch..
20747         }
20748         
20749
20750         if (this.isLocked()) {
20751             //Roo.log('locked');
20752             return;
20753         }
20754
20755         this.DDM.refreshCache(this.groups);
20756 //        Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
20757         var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
20758         if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) )  {
20759             //Roo.log('no outer handes or not over target');
20760                 // do nothing.
20761         } else {
20762 //            Roo.log('check validator');
20763             if (this.clickValidator(e)) {
20764 //                Roo.log('validate success');
20765                 // set the initial element position
20766                 this.setStartPosition();
20767
20768
20769                 this.b4MouseDown(e);
20770                 this.onMouseDown(e);
20771
20772                 this.DDM.handleMouseDown(e, this);
20773
20774                 this.DDM.stopEvent(e);
20775             } else {
20776
20777
20778             }
20779         }
20780     },
20781
20782     clickValidator: function(e) {
20783         var target = e.getTarget();
20784         return ( this.isValidHandleChild(target) &&
20785                     (this.id == this.handleElId ||
20786                         this.DDM.handleWasClicked(target, this.id)) );
20787     },
20788
20789     /**
20790      * Allows you to specify a tag name that should not start a drag operation
20791      * when clicked.  This is designed to facilitate embedding links within a
20792      * drag handle that do something other than start the drag.
20793      * @method addInvalidHandleType
20794      * @param {string} tagName the type of element to exclude
20795      */
20796     addInvalidHandleType: function(tagName) {
20797         var type = tagName.toUpperCase();
20798         this.invalidHandleTypes[type] = type;
20799     },
20800
20801     /**
20802      * Lets you to specify an element id for a child of a drag handle
20803      * that should not initiate a drag
20804      * @method addInvalidHandleId
20805      * @param {string} id the element id of the element you wish to ignore
20806      */
20807     addInvalidHandleId: function(id) {
20808         if (typeof id !== "string") {
20809             id = Roo.id(id);
20810         }
20811         this.invalidHandleIds[id] = id;
20812     },
20813
20814     /**
20815      * Lets you specify a css class of elements that will not initiate a drag
20816      * @method addInvalidHandleClass
20817      * @param {string} cssClass the class of the elements you wish to ignore
20818      */
20819     addInvalidHandleClass: function(cssClass) {
20820         this.invalidHandleClasses.push(cssClass);
20821     },
20822
20823     /**
20824      * Unsets an excluded tag name set by addInvalidHandleType
20825      * @method removeInvalidHandleType
20826      * @param {string} tagName the type of element to unexclude
20827      */
20828     removeInvalidHandleType: function(tagName) {
20829         var type = tagName.toUpperCase();
20830         // this.invalidHandleTypes[type] = null;
20831         delete this.invalidHandleTypes[type];
20832     },
20833
20834     /**
20835      * Unsets an invalid handle id
20836      * @method removeInvalidHandleId
20837      * @param {string} id the id of the element to re-enable
20838      */
20839     removeInvalidHandleId: function(id) {
20840         if (typeof id !== "string") {
20841             id = Roo.id(id);
20842         }
20843         delete this.invalidHandleIds[id];
20844     },
20845
20846     /**
20847      * Unsets an invalid css class
20848      * @method removeInvalidHandleClass
20849      * @param {string} cssClass the class of the element(s) you wish to
20850      * re-enable
20851      */
20852     removeInvalidHandleClass: function(cssClass) {
20853         for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
20854             if (this.invalidHandleClasses[i] == cssClass) {
20855                 delete this.invalidHandleClasses[i];
20856             }
20857         }
20858     },
20859
20860     /**
20861      * Checks the tag exclusion list to see if this click should be ignored
20862      * @method isValidHandleChild
20863      * @param {HTMLElement} node the HTMLElement to evaluate
20864      * @return {boolean} true if this is a valid tag type, false if not
20865      */
20866     isValidHandleChild: function(node) {
20867
20868         var valid = true;
20869         // var n = (node.nodeName == "#text") ? node.parentNode : node;
20870         var nodeName;
20871         try {
20872             nodeName = node.nodeName.toUpperCase();
20873         } catch(e) {
20874             nodeName = node.nodeName;
20875         }
20876         valid = valid && !this.invalidHandleTypes[nodeName];
20877         valid = valid && !this.invalidHandleIds[node.id];
20878
20879         for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
20880             valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
20881         }
20882
20883
20884         return valid;
20885
20886     },
20887
20888     /**
20889      * Create the array of horizontal tick marks if an interval was specified
20890      * in setXConstraint().
20891      * @method setXTicks
20892      * @private
20893      */
20894     setXTicks: function(iStartX, iTickSize) {
20895         this.xTicks = [];
20896         this.xTickSize = iTickSize;
20897
20898         var tickMap = {};
20899
20900         for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
20901             if (!tickMap[i]) {
20902                 this.xTicks[this.xTicks.length] = i;
20903                 tickMap[i] = true;
20904             }
20905         }
20906
20907         for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
20908             if (!tickMap[i]) {
20909                 this.xTicks[this.xTicks.length] = i;
20910                 tickMap[i] = true;
20911             }
20912         }
20913
20914         this.xTicks.sort(this.DDM.numericSort) ;
20915     },
20916
20917     /**
20918      * Create the array of vertical tick marks if an interval was specified in
20919      * setYConstraint().
20920      * @method setYTicks
20921      * @private
20922      */
20923     setYTicks: function(iStartY, iTickSize) {
20924         this.yTicks = [];
20925         this.yTickSize = iTickSize;
20926
20927         var tickMap = {};
20928
20929         for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
20930             if (!tickMap[i]) {
20931                 this.yTicks[this.yTicks.length] = i;
20932                 tickMap[i] = true;
20933             }
20934         }
20935
20936         for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
20937             if (!tickMap[i]) {
20938                 this.yTicks[this.yTicks.length] = i;
20939                 tickMap[i] = true;
20940             }
20941         }
20942
20943         this.yTicks.sort(this.DDM.numericSort) ;
20944     },
20945
20946     /**
20947      * By default, the element can be dragged any place on the screen.  Use
20948      * this method to limit the horizontal travel of the element.  Pass in
20949      * 0,0 for the parameters if you want to lock the drag to the y axis.
20950      * @method setXConstraint
20951      * @param {int} iLeft the number of pixels the element can move to the left
20952      * @param {int} iRight the number of pixels the element can move to the
20953      * right
20954      * @param {int} iTickSize optional parameter for specifying that the
20955      * element
20956      * should move iTickSize pixels at a time.
20957      */
20958     setXConstraint: function(iLeft, iRight, iTickSize) {
20959         this.leftConstraint = iLeft;
20960         this.rightConstraint = iRight;
20961
20962         this.minX = this.initPageX - iLeft;
20963         this.maxX = this.initPageX + iRight;
20964         if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
20965
20966         this.constrainX = true;
20967     },
20968
20969     /**
20970      * Clears any constraints applied to this instance.  Also clears ticks
20971      * since they can't exist independent of a constraint at this time.
20972      * @method clearConstraints
20973      */
20974     clearConstraints: function() {
20975         this.constrainX = false;
20976         this.constrainY = false;
20977         this.clearTicks();
20978     },
20979
20980     /**
20981      * Clears any tick interval defined for this instance
20982      * @method clearTicks
20983      */
20984     clearTicks: function() {
20985         this.xTicks = null;
20986         this.yTicks = null;
20987         this.xTickSize = 0;
20988         this.yTickSize = 0;
20989     },
20990
20991     /**
20992      * By default, the element can be dragged any place on the screen.  Set
20993      * this to limit the vertical travel of the element.  Pass in 0,0 for the
20994      * parameters if you want to lock the drag to the x axis.
20995      * @method setYConstraint
20996      * @param {int} iUp the number of pixels the element can move up
20997      * @param {int} iDown the number of pixels the element can move down
20998      * @param {int} iTickSize optional parameter for specifying that the
20999      * element should move iTickSize pixels at a time.
21000      */
21001     setYConstraint: function(iUp, iDown, iTickSize) {
21002         this.topConstraint = iUp;
21003         this.bottomConstraint = iDown;
21004
21005         this.minY = this.initPageY - iUp;
21006         this.maxY = this.initPageY + iDown;
21007         if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
21008
21009         this.constrainY = true;
21010
21011     },
21012
21013     /**
21014      * resetConstraints must be called if you manually reposition a dd element.
21015      * @method resetConstraints
21016      * @param {boolean} maintainOffset
21017      */
21018     resetConstraints: function() {
21019
21020
21021         // Maintain offsets if necessary
21022         if (this.initPageX || this.initPageX === 0) {
21023             // figure out how much this thing has moved
21024             var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
21025             var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
21026
21027             this.setInitPosition(dx, dy);
21028
21029         // This is the first time we have detected the element's position
21030         } else {
21031             this.setInitPosition();
21032         }
21033
21034         if (this.constrainX) {
21035             this.setXConstraint( this.leftConstraint,
21036                                  this.rightConstraint,
21037                                  this.xTickSize        );
21038         }
21039
21040         if (this.constrainY) {
21041             this.setYConstraint( this.topConstraint,
21042                                  this.bottomConstraint,
21043                                  this.yTickSize         );
21044         }
21045     },
21046
21047     /**
21048      * Normally the drag element is moved pixel by pixel, but we can specify
21049      * that it move a number of pixels at a time.  This method resolves the
21050      * location when we have it set up like this.
21051      * @method getTick
21052      * @param {int} val where we want to place the object
21053      * @param {int[]} tickArray sorted array of valid points
21054      * @return {int} the closest tick
21055      * @private
21056      */
21057     getTick: function(val, tickArray) {
21058
21059         if (!tickArray) {
21060             // If tick interval is not defined, it is effectively 1 pixel,
21061             // so we return the value passed to us.
21062             return val;
21063         } else if (tickArray[0] >= val) {
21064             // The value is lower than the first tick, so we return the first
21065             // tick.
21066             return tickArray[0];
21067         } else {
21068             for (var i=0, len=tickArray.length; i<len; ++i) {
21069                 var next = i + 1;
21070                 if (tickArray[next] && tickArray[next] >= val) {
21071                     var diff1 = val - tickArray[i];
21072                     var diff2 = tickArray[next] - val;
21073                     return (diff2 > diff1) ? tickArray[i] : tickArray[next];
21074                 }
21075             }
21076
21077             // The value is larger than the last tick, so we return the last
21078             // tick.
21079             return tickArray[tickArray.length - 1];
21080         }
21081     },
21082
21083     /**
21084      * toString method
21085      * @method toString
21086      * @return {string} string representation of the dd obj
21087      */
21088     toString: function() {
21089         return ("DragDrop " + this.id);
21090     }
21091
21092 });
21093
21094 })();
21095 /*
21096  * Based on:
21097  * Ext JS Library 1.1.1
21098  * Copyright(c) 2006-2007, Ext JS, LLC.
21099  *
21100  * Originally Released Under LGPL - original licence link has changed is not relivant.
21101  *
21102  * Fork - LGPL
21103  * <script type="text/javascript">
21104  */
21105
21106
21107 /**
21108  * The drag and drop utility provides a framework for building drag and drop
21109  * applications.  In addition to enabling drag and drop for specific elements,
21110  * the drag and drop elements are tracked by the manager class, and the
21111  * interactions between the various elements are tracked during the drag and
21112  * the implementing code is notified about these important moments.
21113  */
21114
21115 // Only load the library once.  Rewriting the manager class would orphan
21116 // existing drag and drop instances.
21117 if (!Roo.dd.DragDropMgr) {
21118
21119 /**
21120  * @class Roo.dd.DragDropMgr
21121  * DragDropMgr is a singleton that tracks the element interaction for
21122  * all DragDrop items in the window.  Generally, you will not call
21123  * this class directly, but it does have helper methods that could
21124  * be useful in your DragDrop implementations.
21125  * @static
21126  */
21127 Roo.dd.DragDropMgr = function() {
21128
21129     var Event = Roo.EventManager;
21130
21131     return {
21132
21133         /**
21134          * Two dimensional Array of registered DragDrop objects.  The first
21135          * dimension is the DragDrop item group, the second the DragDrop
21136          * object.
21137          * @property ids
21138          * @type {string: string}
21139          * @private
21140          * @static
21141          */
21142         ids: {},
21143
21144         /**
21145          * Array of element ids defined as drag handles.  Used to determine
21146          * if the element that generated the mousedown event is actually the
21147          * handle and not the html element itself.
21148          * @property handleIds
21149          * @type {string: string}
21150          * @private
21151          * @static
21152          */
21153         handleIds: {},
21154
21155         /**
21156          * the DragDrop object that is currently being dragged
21157          * @property dragCurrent
21158          * @type DragDrop
21159          * @private
21160          * @static
21161          **/
21162         dragCurrent: null,
21163
21164         /**
21165          * the DragDrop object(s) that are being hovered over
21166          * @property dragOvers
21167          * @type Array
21168          * @private
21169          * @static
21170          */
21171         dragOvers: {},
21172
21173         /**
21174          * the X distance between the cursor and the object being dragged
21175          * @property deltaX
21176          * @type int
21177          * @private
21178          * @static
21179          */
21180         deltaX: 0,
21181
21182         /**
21183          * the Y distance between the cursor and the object being dragged
21184          * @property deltaY
21185          * @type int
21186          * @private
21187          * @static
21188          */
21189         deltaY: 0,
21190
21191         /**
21192          * Flag to determine if we should prevent the default behavior of the
21193          * events we define. By default this is true, but this can be set to
21194          * false if you need the default behavior (not recommended)
21195          * @property preventDefault
21196          * @type boolean
21197          * @static
21198          */
21199         preventDefault: true,
21200
21201         /**
21202          * Flag to determine if we should stop the propagation of the events
21203          * we generate. This is true by default but you may want to set it to
21204          * false if the html element contains other features that require the
21205          * mouse click.
21206          * @property stopPropagation
21207          * @type boolean
21208          * @static
21209          */
21210         stopPropagation: true,
21211
21212         /**
21213          * Internal flag that is set to true when drag and drop has been
21214          * intialized
21215          * @property initialized
21216          * @private
21217          * @static
21218          */
21219         initalized: false,
21220
21221         /**
21222          * All drag and drop can be disabled.
21223          * @property locked
21224          * @private
21225          * @static
21226          */
21227         locked: false,
21228
21229         /**
21230          * Called the first time an element is registered.
21231          * @method init
21232          * @private
21233          * @static
21234          */
21235         init: function() {
21236             this.initialized = true;
21237         },
21238
21239         /**
21240          * In point mode, drag and drop interaction is defined by the
21241          * location of the cursor during the drag/drop
21242          * @property POINT
21243          * @type int
21244          * @static
21245          */
21246         POINT: 0,
21247
21248         /**
21249          * In intersect mode, drag and drop interactio nis defined by the
21250          * overlap of two or more drag and drop objects.
21251          * @property INTERSECT
21252          * @type int
21253          * @static
21254          */
21255         INTERSECT: 1,
21256
21257         /**
21258          * The current drag and drop mode.  Default: POINT
21259          * @property mode
21260          * @type int
21261          * @static
21262          */
21263         mode: 0,
21264
21265         /**
21266          * Runs method on all drag and drop objects
21267          * @method _execOnAll
21268          * @private
21269          * @static
21270          */
21271         _execOnAll: function(sMethod, args) {
21272             for (var i in this.ids) {
21273                 for (var j in this.ids[i]) {
21274                     var oDD = this.ids[i][j];
21275                     if (! this.isTypeOfDD(oDD)) {
21276                         continue;
21277                     }
21278                     oDD[sMethod].apply(oDD, args);
21279                 }
21280             }
21281         },
21282
21283         /**
21284          * Drag and drop initialization.  Sets up the global event handlers
21285          * @method _onLoad
21286          * @private
21287          * @static
21288          */
21289         _onLoad: function() {
21290
21291             this.init();
21292
21293             if (!Roo.isTouch) {
21294                 Event.on(document, "mouseup",   this.handleMouseUp, this, true);
21295                 Event.on(document, "mousemove", this.handleMouseMove, this, true);
21296             }
21297             Event.on(document, "touchend",   this.handleMouseUp, this, true);
21298             Event.on(document, "touchmove", this.handleMouseMove, this, true);
21299             
21300             Event.on(window,   "unload",    this._onUnload, this, true);
21301             Event.on(window,   "resize",    this._onResize, this, true);
21302             // Event.on(window,   "mouseout",    this._test);
21303
21304         },
21305
21306         /**
21307          * Reset constraints on all drag and drop objs
21308          * @method _onResize
21309          * @private
21310          * @static
21311          */
21312         _onResize: function(e) {
21313             this._execOnAll("resetConstraints", []);
21314         },
21315
21316         /**
21317          * Lock all drag and drop functionality
21318          * @method lock
21319          * @static
21320          */
21321         lock: function() { this.locked = true; },
21322
21323         /**
21324          * Unlock all drag and drop functionality
21325          * @method unlock
21326          * @static
21327          */
21328         unlock: function() { this.locked = false; },
21329
21330         /**
21331          * Is drag and drop locked?
21332          * @method isLocked
21333          * @return {boolean} True if drag and drop is locked, false otherwise.
21334          * @static
21335          */
21336         isLocked: function() { return this.locked; },
21337
21338         /**
21339          * Location cache that is set for all drag drop objects when a drag is
21340          * initiated, cleared when the drag is finished.
21341          * @property locationCache
21342          * @private
21343          * @static
21344          */
21345         locationCache: {},
21346
21347         /**
21348          * Set useCache to false if you want to force object the lookup of each
21349          * drag and drop linked element constantly during a drag.
21350          * @property useCache
21351          * @type boolean
21352          * @static
21353          */
21354         useCache: true,
21355
21356         /**
21357          * The number of pixels that the mouse needs to move after the
21358          * mousedown before the drag is initiated.  Default=3;
21359          * @property clickPixelThresh
21360          * @type int
21361          * @static
21362          */
21363         clickPixelThresh: 3,
21364
21365         /**
21366          * The number of milliseconds after the mousedown event to initiate the
21367          * drag if we don't get a mouseup event. Default=1000
21368          * @property clickTimeThresh
21369          * @type int
21370          * @static
21371          */
21372         clickTimeThresh: 350,
21373
21374         /**
21375          * Flag that indicates that either the drag pixel threshold or the
21376          * mousdown time threshold has been met
21377          * @property dragThreshMet
21378          * @type boolean
21379          * @private
21380          * @static
21381          */
21382         dragThreshMet: false,
21383
21384         /**
21385          * Timeout used for the click time threshold
21386          * @property clickTimeout
21387          * @type Object
21388          * @private
21389          * @static
21390          */
21391         clickTimeout: null,
21392
21393         /**
21394          * The X position of the mousedown event stored for later use when a
21395          * drag threshold is met.
21396          * @property startX
21397          * @type int
21398          * @private
21399          * @static
21400          */
21401         startX: 0,
21402
21403         /**
21404          * The Y position of the mousedown event stored for later use when a
21405          * drag threshold is met.
21406          * @property startY
21407          * @type int
21408          * @private
21409          * @static
21410          */
21411         startY: 0,
21412
21413         /**
21414          * Each DragDrop instance must be registered with the DragDropMgr.
21415          * This is executed in DragDrop.init()
21416          * @method regDragDrop
21417          * @param {DragDrop} oDD the DragDrop object to register
21418          * @param {String} sGroup the name of the group this element belongs to
21419          * @static
21420          */
21421         regDragDrop: function(oDD, sGroup) {
21422             if (!this.initialized) { this.init(); }
21423
21424             if (!this.ids[sGroup]) {
21425                 this.ids[sGroup] = {};
21426             }
21427             this.ids[sGroup][oDD.id] = oDD;
21428         },
21429
21430         /**
21431          * Removes the supplied dd instance from the supplied group. Executed
21432          * by DragDrop.removeFromGroup, so don't call this function directly.
21433          * @method removeDDFromGroup
21434          * @private
21435          * @static
21436          */
21437         removeDDFromGroup: function(oDD, sGroup) {
21438             if (!this.ids[sGroup]) {
21439                 this.ids[sGroup] = {};
21440             }
21441
21442             var obj = this.ids[sGroup];
21443             if (obj && obj[oDD.id]) {
21444                 delete obj[oDD.id];
21445             }
21446         },
21447
21448         /**
21449          * Unregisters a drag and drop item.  This is executed in
21450          * DragDrop.unreg, use that method instead of calling this directly.
21451          * @method _remove
21452          * @private
21453          * @static
21454          */
21455         _remove: function(oDD) {
21456             for (var g in oDD.groups) {
21457                 if (g && this.ids[g][oDD.id]) {
21458                     delete this.ids[g][oDD.id];
21459                 }
21460             }
21461             delete this.handleIds[oDD.id];
21462         },
21463
21464         /**
21465          * Each DragDrop handle element must be registered.  This is done
21466          * automatically when executing DragDrop.setHandleElId()
21467          * @method regHandle
21468          * @param {String} sDDId the DragDrop id this element is a handle for
21469          * @param {String} sHandleId the id of the element that is the drag
21470          * handle
21471          * @static
21472          */
21473         regHandle: function(sDDId, sHandleId) {
21474             if (!this.handleIds[sDDId]) {
21475                 this.handleIds[sDDId] = {};
21476             }
21477             this.handleIds[sDDId][sHandleId] = sHandleId;
21478         },
21479
21480         /**
21481          * Utility function to determine if a given element has been
21482          * registered as a drag drop item.
21483          * @method isDragDrop
21484          * @param {String} id the element id to check
21485          * @return {boolean} true if this element is a DragDrop item,
21486          * false otherwise
21487          * @static
21488          */
21489         isDragDrop: function(id) {
21490             return ( this.getDDById(id) ) ? true : false;
21491         },
21492
21493         /**
21494          * Returns the drag and drop instances that are in all groups the
21495          * passed in instance belongs to.
21496          * @method getRelated
21497          * @param {DragDrop} p_oDD the obj to get related data for
21498          * @param {boolean} bTargetsOnly if true, only return targetable objs
21499          * @return {DragDrop[]} the related instances
21500          * @static
21501          */
21502         getRelated: function(p_oDD, bTargetsOnly) {
21503             var oDDs = [];
21504             for (var i in p_oDD.groups) {
21505                 for (j in this.ids[i]) {
21506                     var dd = this.ids[i][j];
21507                     if (! this.isTypeOfDD(dd)) {
21508                         continue;
21509                     }
21510                     if (!bTargetsOnly || dd.isTarget) {
21511                         oDDs[oDDs.length] = dd;
21512                     }
21513                 }
21514             }
21515
21516             return oDDs;
21517         },
21518
21519         /**
21520          * Returns true if the specified dd target is a legal target for
21521          * the specifice drag obj
21522          * @method isLegalTarget
21523          * @param {DragDrop} the drag obj
21524          * @param {DragDrop} the target
21525          * @return {boolean} true if the target is a legal target for the
21526          * dd obj
21527          * @static
21528          */
21529         isLegalTarget: function (oDD, oTargetDD) {
21530             var targets = this.getRelated(oDD, true);
21531             for (var i=0, len=targets.length;i<len;++i) {
21532                 if (targets[i].id == oTargetDD.id) {
21533                     return true;
21534                 }
21535             }
21536
21537             return false;
21538         },
21539
21540         /**
21541          * My goal is to be able to transparently determine if an object is
21542          * typeof DragDrop, and the exact subclass of DragDrop.  typeof
21543          * returns "object", oDD.constructor.toString() always returns
21544          * "DragDrop" and not the name of the subclass.  So for now it just
21545          * evaluates a well-known variable in DragDrop.
21546          * @method isTypeOfDD
21547          * @param {Object} the object to evaluate
21548          * @return {boolean} true if typeof oDD = DragDrop
21549          * @static
21550          */
21551         isTypeOfDD: function (oDD) {
21552             return (oDD && oDD.__ygDragDrop);
21553         },
21554
21555         /**
21556          * Utility function to determine if a given element has been
21557          * registered as a drag drop handle for the given Drag Drop object.
21558          * @method isHandle
21559          * @param {String} id the element id to check
21560          * @return {boolean} true if this element is a DragDrop handle, false
21561          * otherwise
21562          * @static
21563          */
21564         isHandle: function(sDDId, sHandleId) {
21565             return ( this.handleIds[sDDId] &&
21566                             this.handleIds[sDDId][sHandleId] );
21567         },
21568
21569         /**
21570          * Returns the DragDrop instance for a given id
21571          * @method getDDById
21572          * @param {String} id the id of the DragDrop object
21573          * @return {DragDrop} the drag drop object, null if it is not found
21574          * @static
21575          */
21576         getDDById: function(id) {
21577             for (var i in this.ids) {
21578                 if (this.ids[i][id]) {
21579                     return this.ids[i][id];
21580                 }
21581             }
21582             return null;
21583         },
21584
21585         /**
21586          * Fired after a registered DragDrop object gets the mousedown event.
21587          * Sets up the events required to track the object being dragged
21588          * @method handleMouseDown
21589          * @param {Event} e the event
21590          * @param oDD the DragDrop object being dragged
21591          * @private
21592          * @static
21593          */
21594         handleMouseDown: function(e, oDD) {
21595             if(Roo.QuickTips){
21596                 Roo.QuickTips.disable();
21597             }
21598             this.currentTarget = e.getTarget();
21599
21600             this.dragCurrent = oDD;
21601
21602             var el = oDD.getEl();
21603
21604             // track start position
21605             this.startX = e.getPageX();
21606             this.startY = e.getPageY();
21607
21608             this.deltaX = this.startX - el.offsetLeft;
21609             this.deltaY = this.startY - el.offsetTop;
21610
21611             this.dragThreshMet = false;
21612
21613             this.clickTimeout = setTimeout(
21614                     function() {
21615                         var DDM = Roo.dd.DDM;
21616                         DDM.startDrag(DDM.startX, DDM.startY);
21617                     },
21618                     this.clickTimeThresh );
21619         },
21620
21621         /**
21622          * Fired when either the drag pixel threshol or the mousedown hold
21623          * time threshold has been met.
21624          * @method startDrag
21625          * @param x {int} the X position of the original mousedown
21626          * @param y {int} the Y position of the original mousedown
21627          * @static
21628          */
21629         startDrag: function(x, y) {
21630             clearTimeout(this.clickTimeout);
21631             if (this.dragCurrent) {
21632                 this.dragCurrent.b4StartDrag(x, y);
21633                 this.dragCurrent.startDrag(x, y);
21634             }
21635             this.dragThreshMet = true;
21636         },
21637
21638         /**
21639          * Internal function to handle the mouseup event.  Will be invoked
21640          * from the context of the document.
21641          * @method handleMouseUp
21642          * @param {Event} e the event
21643          * @private
21644          * @static
21645          */
21646         handleMouseUp: function(e) {
21647
21648             if(Roo.QuickTips){
21649                 Roo.QuickTips.enable();
21650             }
21651             if (! this.dragCurrent) {
21652                 return;
21653             }
21654
21655             clearTimeout(this.clickTimeout);
21656
21657             if (this.dragThreshMet) {
21658                 this.fireEvents(e, true);
21659             } else {
21660             }
21661
21662             this.stopDrag(e);
21663
21664             this.stopEvent(e);
21665         },
21666
21667         /**
21668          * Utility to stop event propagation and event default, if these
21669          * features are turned on.
21670          * @method stopEvent
21671          * @param {Event} e the event as returned by this.getEvent()
21672          * @static
21673          */
21674         stopEvent: function(e){
21675             if(this.stopPropagation) {
21676                 e.stopPropagation();
21677             }
21678
21679             if (this.preventDefault) {
21680                 e.preventDefault();
21681             }
21682         },
21683
21684         /**
21685          * Internal function to clean up event handlers after the drag
21686          * operation is complete
21687          * @method stopDrag
21688          * @param {Event} e the event
21689          * @private
21690          * @static
21691          */
21692         stopDrag: function(e) {
21693             // Fire the drag end event for the item that was dragged
21694             if (this.dragCurrent) {
21695                 if (this.dragThreshMet) {
21696                     this.dragCurrent.b4EndDrag(e);
21697                     this.dragCurrent.endDrag(e);
21698                 }
21699
21700                 this.dragCurrent.onMouseUp(e);
21701             }
21702
21703             this.dragCurrent = null;
21704             this.dragOvers = {};
21705         },
21706
21707         /**
21708          * Internal function to handle the mousemove event.  Will be invoked
21709          * from the context of the html element.
21710          *
21711          * @TODO figure out what we can do about mouse events lost when the
21712          * user drags objects beyond the window boundary.  Currently we can
21713          * detect this in internet explorer by verifying that the mouse is
21714          * down during the mousemove event.  Firefox doesn't give us the
21715          * button state on the mousemove event.
21716          * @method handleMouseMove
21717          * @param {Event} e the event
21718          * @private
21719          * @static
21720          */
21721         handleMouseMove: function(e) {
21722             if (! this.dragCurrent) {
21723                 return true;
21724             }
21725
21726             // var button = e.which || e.button;
21727
21728             // check for IE mouseup outside of page boundary
21729             if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
21730                 this.stopEvent(e);
21731                 return this.handleMouseUp(e);
21732             }
21733
21734             if (!this.dragThreshMet) {
21735                 var diffX = Math.abs(this.startX - e.getPageX());
21736                 var diffY = Math.abs(this.startY - e.getPageY());
21737                 if (diffX > this.clickPixelThresh ||
21738                             diffY > this.clickPixelThresh) {
21739                     this.startDrag(this.startX, this.startY);
21740                 }
21741             }
21742
21743             if (this.dragThreshMet) {
21744                 this.dragCurrent.b4Drag(e);
21745                 this.dragCurrent.onDrag(e);
21746                 if(!this.dragCurrent.moveOnly){
21747                     this.fireEvents(e, false);
21748                 }
21749             }
21750
21751             this.stopEvent(e);
21752
21753             return true;
21754         },
21755
21756         /**
21757          * Iterates over all of the DragDrop elements to find ones we are
21758          * hovering over or dropping on
21759          * @method fireEvents
21760          * @param {Event} e the event
21761          * @param {boolean} isDrop is this a drop op or a mouseover op?
21762          * @private
21763          * @static
21764          */
21765         fireEvents: function(e, isDrop) {
21766             var dc = this.dragCurrent;
21767
21768             // If the user did the mouse up outside of the window, we could
21769             // get here even though we have ended the drag.
21770             if (!dc || dc.isLocked()) {
21771                 return;
21772             }
21773
21774             var pt = e.getPoint();
21775
21776             // cache the previous dragOver array
21777             var oldOvers = [];
21778
21779             var outEvts   = [];
21780             var overEvts  = [];
21781             var dropEvts  = [];
21782             var enterEvts = [];
21783
21784             // Check to see if the object(s) we were hovering over is no longer
21785             // being hovered over so we can fire the onDragOut event
21786             for (var i in this.dragOvers) {
21787
21788                 var ddo = this.dragOvers[i];
21789
21790                 if (! this.isTypeOfDD(ddo)) {
21791                     continue;
21792                 }
21793
21794                 if (! this.isOverTarget(pt, ddo, this.mode)) {
21795                     outEvts.push( ddo );
21796                 }
21797
21798                 oldOvers[i] = true;
21799                 delete this.dragOvers[i];
21800             }
21801
21802             for (var sGroup in dc.groups) {
21803
21804                 if ("string" != typeof sGroup) {
21805                     continue;
21806                 }
21807
21808                 for (i in this.ids[sGroup]) {
21809                     var oDD = this.ids[sGroup][i];
21810                     if (! this.isTypeOfDD(oDD)) {
21811                         continue;
21812                     }
21813
21814                     if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
21815                         if (this.isOverTarget(pt, oDD, this.mode)) {
21816                             // look for drop interactions
21817                             if (isDrop) {
21818                                 dropEvts.push( oDD );
21819                             // look for drag enter and drag over interactions
21820                             } else {
21821
21822                                 // initial drag over: dragEnter fires
21823                                 if (!oldOvers[oDD.id]) {
21824                                     enterEvts.push( oDD );
21825                                 // subsequent drag overs: dragOver fires
21826                                 } else {
21827                                     overEvts.push( oDD );
21828                                 }
21829
21830                                 this.dragOvers[oDD.id] = oDD;
21831                             }
21832                         }
21833                     }
21834                 }
21835             }
21836
21837             if (this.mode) {
21838                 if (outEvts.length) {
21839                     dc.b4DragOut(e, outEvts);
21840                     dc.onDragOut(e, outEvts);
21841                 }
21842
21843                 if (enterEvts.length) {
21844                     dc.onDragEnter(e, enterEvts);
21845                 }
21846
21847                 if (overEvts.length) {
21848                     dc.b4DragOver(e, overEvts);
21849                     dc.onDragOver(e, overEvts);
21850                 }
21851
21852                 if (dropEvts.length) {
21853                     dc.b4DragDrop(e, dropEvts);
21854                     dc.onDragDrop(e, dropEvts);
21855                 }
21856
21857             } else {
21858                 // fire dragout events
21859                 var len = 0;
21860                 for (i=0, len=outEvts.length; i<len; ++i) {
21861                     dc.b4DragOut(e, outEvts[i].id);
21862                     dc.onDragOut(e, outEvts[i].id);
21863                 }
21864
21865                 // fire enter events
21866                 for (i=0,len=enterEvts.length; i<len; ++i) {
21867                     // dc.b4DragEnter(e, oDD.id);
21868                     dc.onDragEnter(e, enterEvts[i].id);
21869                 }
21870
21871                 // fire over events
21872                 for (i=0,len=overEvts.length; i<len; ++i) {
21873                     dc.b4DragOver(e, overEvts[i].id);
21874                     dc.onDragOver(e, overEvts[i].id);
21875                 }
21876
21877                 // fire drop events
21878                 for (i=0, len=dropEvts.length; i<len; ++i) {
21879                     dc.b4DragDrop(e, dropEvts[i].id);
21880                     dc.onDragDrop(e, dropEvts[i].id);
21881                 }
21882
21883             }
21884
21885             // notify about a drop that did not find a target
21886             if (isDrop && !dropEvts.length) {
21887                 dc.onInvalidDrop(e);
21888             }
21889
21890         },
21891
21892         /**
21893          * Helper function for getting the best match from the list of drag
21894          * and drop objects returned by the drag and drop events when we are
21895          * in INTERSECT mode.  It returns either the first object that the
21896          * cursor is over, or the object that has the greatest overlap with
21897          * the dragged element.
21898          * @method getBestMatch
21899          * @param  {DragDrop[]} dds The array of drag and drop objects
21900          * targeted
21901          * @return {DragDrop}       The best single match
21902          * @static
21903          */
21904         getBestMatch: function(dds) {
21905             var winner = null;
21906             // Return null if the input is not what we expect
21907             //if (!dds || !dds.length || dds.length == 0) {
21908                // winner = null;
21909             // If there is only one item, it wins
21910             //} else if (dds.length == 1) {
21911
21912             var len = dds.length;
21913
21914             if (len == 1) {
21915                 winner = dds[0];
21916             } else {
21917                 // Loop through the targeted items
21918                 for (var i=0; i<len; ++i) {
21919                     var dd = dds[i];
21920                     // If the cursor is over the object, it wins.  If the
21921                     // cursor is over multiple matches, the first one we come
21922                     // to wins.
21923                     if (dd.cursorIsOver) {
21924                         winner = dd;
21925                         break;
21926                     // Otherwise the object with the most overlap wins
21927                     } else {
21928                         if (!winner ||
21929                             winner.overlap.getArea() < dd.overlap.getArea()) {
21930                             winner = dd;
21931                         }
21932                     }
21933                 }
21934             }
21935
21936             return winner;
21937         },
21938
21939         /**
21940          * Refreshes the cache of the top-left and bottom-right points of the
21941          * drag and drop objects in the specified group(s).  This is in the
21942          * format that is stored in the drag and drop instance, so typical
21943          * usage is:
21944          * <code>
21945          * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
21946          * </code>
21947          * Alternatively:
21948          * <code>
21949          * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
21950          * </code>
21951          * @TODO this really should be an indexed array.  Alternatively this
21952          * method could accept both.
21953          * @method refreshCache
21954          * @param {Object} groups an associative array of groups to refresh
21955          * @static
21956          */
21957         refreshCache: function(groups) {
21958             for (var sGroup in groups) {
21959                 if ("string" != typeof sGroup) {
21960                     continue;
21961                 }
21962                 for (var i in this.ids[sGroup]) {
21963                     var oDD = this.ids[sGroup][i];
21964
21965                     if (this.isTypeOfDD(oDD)) {
21966                     // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
21967                         var loc = this.getLocation(oDD);
21968                         if (loc) {
21969                             this.locationCache[oDD.id] = loc;
21970                         } else {
21971                             delete this.locationCache[oDD.id];
21972                             // this will unregister the drag and drop object if
21973                             // the element is not in a usable state
21974                             // oDD.unreg();
21975                         }
21976                     }
21977                 }
21978             }
21979         },
21980
21981         /**
21982          * This checks to make sure an element exists and is in the DOM.  The
21983          * main purpose is to handle cases where innerHTML is used to remove
21984          * drag and drop objects from the DOM.  IE provides an 'unspecified
21985          * error' when trying to access the offsetParent of such an element
21986          * @method verifyEl
21987          * @param {HTMLElement} el the element to check
21988          * @return {boolean} true if the element looks usable
21989          * @static
21990          */
21991         verifyEl: function(el) {
21992             if (el) {
21993                 var parent;
21994                 if(Roo.isIE){
21995                     try{
21996                         parent = el.offsetParent;
21997                     }catch(e){}
21998                 }else{
21999                     parent = el.offsetParent;
22000                 }
22001                 if (parent) {
22002                     return true;
22003                 }
22004             }
22005
22006             return false;
22007         },
22008
22009         /**
22010          * Returns a Region object containing the drag and drop element's position
22011          * and size, including the padding configured for it
22012          * @method getLocation
22013          * @param {DragDrop} oDD the drag and drop object to get the
22014          *                       location for
22015          * @return {Roo.lib.Region} a Region object representing the total area
22016          *                             the element occupies, including any padding
22017          *                             the instance is configured for.
22018          * @static
22019          */
22020         getLocation: function(oDD) {
22021             if (! this.isTypeOfDD(oDD)) {
22022                 return null;
22023             }
22024
22025             var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
22026
22027             try {
22028                 pos= Roo.lib.Dom.getXY(el);
22029             } catch (e) { }
22030
22031             if (!pos) {
22032                 return null;
22033             }
22034
22035             x1 = pos[0];
22036             x2 = x1 + el.offsetWidth;
22037             y1 = pos[1];
22038             y2 = y1 + el.offsetHeight;
22039
22040             t = y1 - oDD.padding[0];
22041             r = x2 + oDD.padding[1];
22042             b = y2 + oDD.padding[2];
22043             l = x1 - oDD.padding[3];
22044
22045             return new Roo.lib.Region( t, r, b, l );
22046         },
22047
22048         /**
22049          * Checks the cursor location to see if it over the target
22050          * @method isOverTarget
22051          * @param {Roo.lib.Point} pt The point to evaluate
22052          * @param {DragDrop} oTarget the DragDrop object we are inspecting
22053          * @return {boolean} true if the mouse is over the target
22054          * @private
22055          * @static
22056          */
22057         isOverTarget: function(pt, oTarget, intersect) {
22058             // use cache if available
22059             var loc = this.locationCache[oTarget.id];
22060             if (!loc || !this.useCache) {
22061                 loc = this.getLocation(oTarget);
22062                 this.locationCache[oTarget.id] = loc;
22063
22064             }
22065
22066             if (!loc) {
22067                 return false;
22068             }
22069
22070             oTarget.cursorIsOver = loc.contains( pt );
22071
22072             // DragDrop is using this as a sanity check for the initial mousedown
22073             // in this case we are done.  In POINT mode, if the drag obj has no
22074             // contraints, we are also done. Otherwise we need to evaluate the
22075             // location of the target as related to the actual location of the
22076             // dragged element.
22077             var dc = this.dragCurrent;
22078             if (!dc || !dc.getTargetCoord ||
22079                     (!intersect && !dc.constrainX && !dc.constrainY)) {
22080                 return oTarget.cursorIsOver;
22081             }
22082
22083             oTarget.overlap = null;
22084
22085             // Get the current location of the drag element, this is the
22086             // location of the mouse event less the delta that represents
22087             // where the original mousedown happened on the element.  We
22088             // need to consider constraints and ticks as well.
22089             var pos = dc.getTargetCoord(pt.x, pt.y);
22090
22091             var el = dc.getDragEl();
22092             var curRegion = new Roo.lib.Region( pos.y,
22093                                                    pos.x + el.offsetWidth,
22094                                                    pos.y + el.offsetHeight,
22095                                                    pos.x );
22096
22097             var overlap = curRegion.intersect(loc);
22098
22099             if (overlap) {
22100                 oTarget.overlap = overlap;
22101                 return (intersect) ? true : oTarget.cursorIsOver;
22102             } else {
22103                 return false;
22104             }
22105         },
22106
22107         /**
22108          * unload event handler
22109          * @method _onUnload
22110          * @private
22111          * @static
22112          */
22113         _onUnload: function(e, me) {
22114             Roo.dd.DragDropMgr.unregAll();
22115         },
22116
22117         /**
22118          * Cleans up the drag and drop events and objects.
22119          * @method unregAll
22120          * @private
22121          * @static
22122          */
22123         unregAll: function() {
22124
22125             if (this.dragCurrent) {
22126                 this.stopDrag();
22127                 this.dragCurrent = null;
22128             }
22129
22130             this._execOnAll("unreg", []);
22131
22132             for (i in this.elementCache) {
22133                 delete this.elementCache[i];
22134             }
22135
22136             this.elementCache = {};
22137             this.ids = {};
22138         },
22139
22140         /**
22141          * A cache of DOM elements
22142          * @property elementCache
22143          * @private
22144          * @static
22145          */
22146         elementCache: {},
22147
22148         /**
22149          * Get the wrapper for the DOM element specified
22150          * @method getElWrapper
22151          * @param {String} id the id of the element to get
22152          * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
22153          * @private
22154          * @deprecated This wrapper isn't that useful
22155          * @static
22156          */
22157         getElWrapper: function(id) {
22158             var oWrapper = this.elementCache[id];
22159             if (!oWrapper || !oWrapper.el) {
22160                 oWrapper = this.elementCache[id] =
22161                     new this.ElementWrapper(Roo.getDom(id));
22162             }
22163             return oWrapper;
22164         },
22165
22166         /**
22167          * Returns the actual DOM element
22168          * @method getElement
22169          * @param {String} id the id of the elment to get
22170          * @return {Object} The element
22171          * @deprecated use Roo.getDom instead
22172          * @static
22173          */
22174         getElement: function(id) {
22175             return Roo.getDom(id);
22176         },
22177
22178         /**
22179          * Returns the style property for the DOM element (i.e.,
22180          * document.getElById(id).style)
22181          * @method getCss
22182          * @param {String} id the id of the elment to get
22183          * @return {Object} The style property of the element
22184          * @deprecated use Roo.getDom instead
22185          * @static
22186          */
22187         getCss: function(id) {
22188             var el = Roo.getDom(id);
22189             return (el) ? el.style : null;
22190         },
22191
22192         /**
22193          * Inner class for cached elements
22194          * @class DragDropMgr.ElementWrapper
22195          * @for DragDropMgr
22196          * @private
22197          * @deprecated
22198          */
22199         ElementWrapper: function(el) {
22200                 /**
22201                  * The element
22202                  * @property el
22203                  */
22204                 this.el = el || null;
22205                 /**
22206                  * The element id
22207                  * @property id
22208                  */
22209                 this.id = this.el && el.id;
22210                 /**
22211                  * A reference to the style property
22212                  * @property css
22213                  */
22214                 this.css = this.el && el.style;
22215             },
22216
22217         /**
22218          * Returns the X position of an html element
22219          * @method getPosX
22220          * @param el the element for which to get the position
22221          * @return {int} the X coordinate
22222          * @for DragDropMgr
22223          * @deprecated use Roo.lib.Dom.getX instead
22224          * @static
22225          */
22226         getPosX: function(el) {
22227             return Roo.lib.Dom.getX(el);
22228         },
22229
22230         /**
22231          * Returns the Y position of an html element
22232          * @method getPosY
22233          * @param el the element for which to get the position
22234          * @return {int} the Y coordinate
22235          * @deprecated use Roo.lib.Dom.getY instead
22236          * @static
22237          */
22238         getPosY: function(el) {
22239             return Roo.lib.Dom.getY(el);
22240         },
22241
22242         /**
22243          * Swap two nodes.  In IE, we use the native method, for others we
22244          * emulate the IE behavior
22245          * @method swapNode
22246          * @param n1 the first node to swap
22247          * @param n2 the other node to swap
22248          * @static
22249          */
22250         swapNode: function(n1, n2) {
22251             if (n1.swapNode) {
22252                 n1.swapNode(n2);
22253             } else {
22254                 var p = n2.parentNode;
22255                 var s = n2.nextSibling;
22256
22257                 if (s == n1) {
22258                     p.insertBefore(n1, n2);
22259                 } else if (n2 == n1.nextSibling) {
22260                     p.insertBefore(n2, n1);
22261                 } else {
22262                     n1.parentNode.replaceChild(n2, n1);
22263                     p.insertBefore(n1, s);
22264                 }
22265             }
22266         },
22267
22268         /**
22269          * Returns the current scroll position
22270          * @method getScroll
22271          * @private
22272          * @static
22273          */
22274         getScroll: function () {
22275             var t, l, dde=document.documentElement, db=document.body;
22276             if (dde && (dde.scrollTop || dde.scrollLeft)) {
22277                 t = dde.scrollTop;
22278                 l = dde.scrollLeft;
22279             } else if (db) {
22280                 t = db.scrollTop;
22281                 l = db.scrollLeft;
22282             } else {
22283
22284             }
22285             return { top: t, left: l };
22286         },
22287
22288         /**
22289          * Returns the specified element style property
22290          * @method getStyle
22291          * @param {HTMLElement} el          the element
22292          * @param {string}      styleProp   the style property
22293          * @return {string} The value of the style property
22294          * @deprecated use Roo.lib.Dom.getStyle
22295          * @static
22296          */
22297         getStyle: function(el, styleProp) {
22298             return Roo.fly(el).getStyle(styleProp);
22299         },
22300
22301         /**
22302          * Gets the scrollTop
22303          * @method getScrollTop
22304          * @return {int} the document's scrollTop
22305          * @static
22306          */
22307         getScrollTop: function () { return this.getScroll().top; },
22308
22309         /**
22310          * Gets the scrollLeft
22311          * @method getScrollLeft
22312          * @return {int} the document's scrollTop
22313          * @static
22314          */
22315         getScrollLeft: function () { return this.getScroll().left; },
22316
22317         /**
22318          * Sets the x/y position of an element to the location of the
22319          * target element.
22320          * @method moveToEl
22321          * @param {HTMLElement} moveEl      The element to move
22322          * @param {HTMLElement} targetEl    The position reference element
22323          * @static
22324          */
22325         moveToEl: function (moveEl, targetEl) {
22326             var aCoord = Roo.lib.Dom.getXY(targetEl);
22327             Roo.lib.Dom.setXY(moveEl, aCoord);
22328         },
22329
22330         /**
22331          * Numeric array sort function
22332          * @method numericSort
22333          * @static
22334          */
22335         numericSort: function(a, b) { return (a - b); },
22336
22337         /**
22338          * Internal counter
22339          * @property _timeoutCount
22340          * @private
22341          * @static
22342          */
22343         _timeoutCount: 0,
22344
22345         /**
22346          * Trying to make the load order less important.  Without this we get
22347          * an error if this file is loaded before the Event Utility.
22348          * @method _addListeners
22349          * @private
22350          * @static
22351          */
22352         _addListeners: function() {
22353             var DDM = Roo.dd.DDM;
22354             if ( Roo.lib.Event && document ) {
22355                 DDM._onLoad();
22356             } else {
22357                 if (DDM._timeoutCount > 2000) {
22358                 } else {
22359                     setTimeout(DDM._addListeners, 10);
22360                     if (document && document.body) {
22361                         DDM._timeoutCount += 1;
22362                     }
22363                 }
22364             }
22365         },
22366
22367         /**
22368          * Recursively searches the immediate parent and all child nodes for
22369          * the handle element in order to determine wheter or not it was
22370          * clicked.
22371          * @method handleWasClicked
22372          * @param node the html element to inspect
22373          * @static
22374          */
22375         handleWasClicked: function(node, id) {
22376             if (this.isHandle(id, node.id)) {
22377                 return true;
22378             } else {
22379                 // check to see if this is a text node child of the one we want
22380                 var p = node.parentNode;
22381
22382                 while (p) {
22383                     if (this.isHandle(id, p.id)) {
22384                         return true;
22385                     } else {
22386                         p = p.parentNode;
22387                     }
22388                 }
22389             }
22390
22391             return false;
22392         }
22393
22394     };
22395
22396 }();
22397
22398 // shorter alias, save a few bytes
22399 Roo.dd.DDM = Roo.dd.DragDropMgr;
22400 Roo.dd.DDM._addListeners();
22401
22402 }/*
22403  * Based on:
22404  * Ext JS Library 1.1.1
22405  * Copyright(c) 2006-2007, Ext JS, LLC.
22406  *
22407  * Originally Released Under LGPL - original licence link has changed is not relivant.
22408  *
22409  * Fork - LGPL
22410  * <script type="text/javascript">
22411  */
22412
22413 /**
22414  * @class Roo.dd.DD
22415  * A DragDrop implementation where the linked element follows the
22416  * mouse cursor during a drag.
22417  * @extends Roo.dd.DragDrop
22418  * @constructor
22419  * @param {String} id the id of the linked element
22420  * @param {String} sGroup the group of related DragDrop items
22421  * @param {object} config an object containing configurable attributes
22422  *                Valid properties for DD:
22423  *                    scroll
22424  */
22425 Roo.dd.DD = function(id, sGroup, config) {
22426     if (id) {
22427         this.init(id, sGroup, config);
22428     }
22429 };
22430
22431 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
22432
22433     /**
22434      * When set to true, the utility automatically tries to scroll the browser
22435      * window wehn a drag and drop element is dragged near the viewport boundary.
22436      * Defaults to true.
22437      * @property scroll
22438      * @type boolean
22439      */
22440     scroll: true,
22441
22442     /**
22443      * Sets the pointer offset to the distance between the linked element's top
22444      * left corner and the location the element was clicked
22445      * @method autoOffset
22446      * @param {int} iPageX the X coordinate of the click
22447      * @param {int} iPageY the Y coordinate of the click
22448      */
22449     autoOffset: function(iPageX, iPageY) {
22450         var x = iPageX - this.startPageX;
22451         var y = iPageY - this.startPageY;
22452         this.setDelta(x, y);
22453     },
22454
22455     /**
22456      * Sets the pointer offset.  You can call this directly to force the
22457      * offset to be in a particular location (e.g., pass in 0,0 to set it
22458      * to the center of the object)
22459      * @method setDelta
22460      * @param {int} iDeltaX the distance from the left
22461      * @param {int} iDeltaY the distance from the top
22462      */
22463     setDelta: function(iDeltaX, iDeltaY) {
22464         this.deltaX = iDeltaX;
22465         this.deltaY = iDeltaY;
22466     },
22467
22468     /**
22469      * Sets the drag element to the location of the mousedown or click event,
22470      * maintaining the cursor location relative to the location on the element
22471      * that was clicked.  Override this if you want to place the element in a
22472      * location other than where the cursor is.
22473      * @method setDragElPos
22474      * @param {int} iPageX the X coordinate of the mousedown or drag event
22475      * @param {int} iPageY the Y coordinate of the mousedown or drag event
22476      */
22477     setDragElPos: function(iPageX, iPageY) {
22478         // the first time we do this, we are going to check to make sure
22479         // the element has css positioning
22480
22481         var el = this.getDragEl();
22482         this.alignElWithMouse(el, iPageX, iPageY);
22483     },
22484
22485     /**
22486      * Sets the element to the location of the mousedown or click event,
22487      * maintaining the cursor location relative to the location on the element
22488      * that was clicked.  Override this if you want to place the element in a
22489      * location other than where the cursor is.
22490      * @method alignElWithMouse
22491      * @param {HTMLElement} el the element to move
22492      * @param {int} iPageX the X coordinate of the mousedown or drag event
22493      * @param {int} iPageY the Y coordinate of the mousedown or drag event
22494      */
22495     alignElWithMouse: function(el, iPageX, iPageY) {
22496         var oCoord = this.getTargetCoord(iPageX, iPageY);
22497         var fly = el.dom ? el : Roo.fly(el);
22498         if (!this.deltaSetXY) {
22499             var aCoord = [oCoord.x, oCoord.y];
22500             fly.setXY(aCoord);
22501             var newLeft = fly.getLeft(true);
22502             var newTop  = fly.getTop(true);
22503             this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
22504         } else {
22505             fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
22506         }
22507
22508         this.cachePosition(oCoord.x, oCoord.y);
22509         this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
22510         return oCoord;
22511     },
22512
22513     /**
22514      * Saves the most recent position so that we can reset the constraints and
22515      * tick marks on-demand.  We need to know this so that we can calculate the
22516      * number of pixels the element is offset from its original position.
22517      * @method cachePosition
22518      * @param iPageX the current x position (optional, this just makes it so we
22519      * don't have to look it up again)
22520      * @param iPageY the current y position (optional, this just makes it so we
22521      * don't have to look it up again)
22522      */
22523     cachePosition: function(iPageX, iPageY) {
22524         if (iPageX) {
22525             this.lastPageX = iPageX;
22526             this.lastPageY = iPageY;
22527         } else {
22528             var aCoord = Roo.lib.Dom.getXY(this.getEl());
22529             this.lastPageX = aCoord[0];
22530             this.lastPageY = aCoord[1];
22531         }
22532     },
22533
22534     /**
22535      * Auto-scroll the window if the dragged object has been moved beyond the
22536      * visible window boundary.
22537      * @method autoScroll
22538      * @param {int} x the drag element's x position
22539      * @param {int} y the drag element's y position
22540      * @param {int} h the height of the drag element
22541      * @param {int} w the width of the drag element
22542      * @private
22543      */
22544     autoScroll: function(x, y, h, w) {
22545
22546         if (this.scroll) {
22547             // The client height
22548             var clientH = Roo.lib.Dom.getViewWidth();
22549
22550             // The client width
22551             var clientW = Roo.lib.Dom.getViewHeight();
22552
22553             // The amt scrolled down
22554             var st = this.DDM.getScrollTop();
22555
22556             // The amt scrolled right
22557             var sl = this.DDM.getScrollLeft();
22558
22559             // Location of the bottom of the element
22560             var bot = h + y;
22561
22562             // Location of the right of the element
22563             var right = w + x;
22564
22565             // The distance from the cursor to the bottom of the visible area,
22566             // adjusted so that we don't scroll if the cursor is beyond the
22567             // element drag constraints
22568             var toBot = (clientH + st - y - this.deltaY);
22569
22570             // The distance from the cursor to the right of the visible area
22571             var toRight = (clientW + sl - x - this.deltaX);
22572
22573
22574             // How close to the edge the cursor must be before we scroll
22575             // var thresh = (document.all) ? 100 : 40;
22576             var thresh = 40;
22577
22578             // How many pixels to scroll per autoscroll op.  This helps to reduce
22579             // clunky scrolling. IE is more sensitive about this ... it needs this
22580             // value to be higher.
22581             var scrAmt = (document.all) ? 80 : 30;
22582
22583             // Scroll down if we are near the bottom of the visible page and the
22584             // obj extends below the crease
22585             if ( bot > clientH && toBot < thresh ) {
22586                 window.scrollTo(sl, st + scrAmt);
22587             }
22588
22589             // Scroll up if the window is scrolled down and the top of the object
22590             // goes above the top border
22591             if ( y < st && st > 0 && y - st < thresh ) {
22592                 window.scrollTo(sl, st - scrAmt);
22593             }
22594
22595             // Scroll right if the obj is beyond the right border and the cursor is
22596             // near the border.
22597             if ( right > clientW && toRight < thresh ) {
22598                 window.scrollTo(sl + scrAmt, st);
22599             }
22600
22601             // Scroll left if the window has been scrolled to the right and the obj
22602             // extends past the left border
22603             if ( x < sl && sl > 0 && x - sl < thresh ) {
22604                 window.scrollTo(sl - scrAmt, st);
22605             }
22606         }
22607     },
22608
22609     /**
22610      * Finds the location the element should be placed if we want to move
22611      * it to where the mouse location less the click offset would place us.
22612      * @method getTargetCoord
22613      * @param {int} iPageX the X coordinate of the click
22614      * @param {int} iPageY the Y coordinate of the click
22615      * @return an object that contains the coordinates (Object.x and Object.y)
22616      * @private
22617      */
22618     getTargetCoord: function(iPageX, iPageY) {
22619
22620
22621         var x = iPageX - this.deltaX;
22622         var y = iPageY - this.deltaY;
22623
22624         if (this.constrainX) {
22625             if (x < this.minX) { x = this.minX; }
22626             if (x > this.maxX) { x = this.maxX; }
22627         }
22628
22629         if (this.constrainY) {
22630             if (y < this.minY) { y = this.minY; }
22631             if (y > this.maxY) { y = this.maxY; }
22632         }
22633
22634         x = this.getTick(x, this.xTicks);
22635         y = this.getTick(y, this.yTicks);
22636
22637
22638         return {x:x, y:y};
22639     },
22640
22641     /*
22642      * Sets up config options specific to this class. Overrides
22643      * Roo.dd.DragDrop, but all versions of this method through the
22644      * inheritance chain are called
22645      */
22646     applyConfig: function() {
22647         Roo.dd.DD.superclass.applyConfig.call(this);
22648         this.scroll = (this.config.scroll !== false);
22649     },
22650
22651     /*
22652      * Event that fires prior to the onMouseDown event.  Overrides
22653      * Roo.dd.DragDrop.
22654      */
22655     b4MouseDown: function(e) {
22656         // this.resetConstraints();
22657         this.autoOffset(e.getPageX(),
22658                             e.getPageY());
22659     },
22660
22661     /*
22662      * Event that fires prior to the onDrag event.  Overrides
22663      * Roo.dd.DragDrop.
22664      */
22665     b4Drag: function(e) {
22666         this.setDragElPos(e.getPageX(),
22667                             e.getPageY());
22668     },
22669
22670     toString: function() {
22671         return ("DD " + this.id);
22672     }
22673
22674     //////////////////////////////////////////////////////////////////////////
22675     // Debugging ygDragDrop events that can be overridden
22676     //////////////////////////////////////////////////////////////////////////
22677     /*
22678     startDrag: function(x, y) {
22679     },
22680
22681     onDrag: function(e) {
22682     },
22683
22684     onDragEnter: function(e, id) {
22685     },
22686
22687     onDragOver: function(e, id) {
22688     },
22689
22690     onDragOut: function(e, id) {
22691     },
22692
22693     onDragDrop: function(e, id) {
22694     },
22695
22696     endDrag: function(e) {
22697     }
22698
22699     */
22700
22701 });/*
22702  * Based on:
22703  * Ext JS Library 1.1.1
22704  * Copyright(c) 2006-2007, Ext JS, LLC.
22705  *
22706  * Originally Released Under LGPL - original licence link has changed is not relivant.
22707  *
22708  * Fork - LGPL
22709  * <script type="text/javascript">
22710  */
22711
22712 /**
22713  * @class Roo.dd.DDProxy
22714  * A DragDrop implementation that inserts an empty, bordered div into
22715  * the document that follows the cursor during drag operations.  At the time of
22716  * the click, the frame div is resized to the dimensions of the linked html
22717  * element, and moved to the exact location of the linked element.
22718  *
22719  * References to the "frame" element refer to the single proxy element that
22720  * was created to be dragged in place of all DDProxy elements on the
22721  * page.
22722  *
22723  * @extends Roo.dd.DD
22724  * @constructor
22725  * @param {String} id the id of the linked html element
22726  * @param {String} sGroup the group of related DragDrop objects
22727  * @param {object} config an object containing configurable attributes
22728  *                Valid properties for DDProxy in addition to those in DragDrop:
22729  *                   resizeFrame, centerFrame, dragElId
22730  */
22731 Roo.dd.DDProxy = function(id, sGroup, config) {
22732     if (id) {
22733         this.init(id, sGroup, config);
22734         this.initFrame();
22735     }
22736 };
22737
22738 /**
22739  * The default drag frame div id
22740  * @property Roo.dd.DDProxy.dragElId
22741  * @type String
22742  * @static
22743  */
22744 Roo.dd.DDProxy.dragElId = "ygddfdiv";
22745
22746 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
22747
22748     /**
22749      * By default we resize the drag frame to be the same size as the element
22750      * we want to drag (this is to get the frame effect).  We can turn it off
22751      * if we want a different behavior.
22752      * @property resizeFrame
22753      * @type boolean
22754      */
22755     resizeFrame: true,
22756
22757     /**
22758      * By default the frame is positioned exactly where the drag element is, so
22759      * we use the cursor offset provided by Roo.dd.DD.  Another option that works only if
22760      * you do not have constraints on the obj is to have the drag frame centered
22761      * around the cursor.  Set centerFrame to true for this effect.
22762      * @property centerFrame
22763      * @type boolean
22764      */
22765     centerFrame: false,
22766
22767     /**
22768      * Creates the proxy element if it does not yet exist
22769      * @method createFrame
22770      */
22771     createFrame: function() {
22772         var self = this;
22773         var body = document.body;
22774
22775         if (!body || !body.firstChild) {
22776             setTimeout( function() { self.createFrame(); }, 50 );
22777             return;
22778         }
22779
22780         var div = this.getDragEl();
22781
22782         if (!div) {
22783             div    = document.createElement("div");
22784             div.id = this.dragElId;
22785             var s  = div.style;
22786
22787             s.position   = "absolute";
22788             s.visibility = "hidden";
22789             s.cursor     = "move";
22790             s.border     = "2px solid #aaa";
22791             s.zIndex     = 999;
22792
22793             // appendChild can blow up IE if invoked prior to the window load event
22794             // while rendering a table.  It is possible there are other scenarios
22795             // that would cause this to happen as well.
22796             body.insertBefore(div, body.firstChild);
22797         }
22798     },
22799
22800     /**
22801      * Initialization for the drag frame element.  Must be called in the
22802      * constructor of all subclasses
22803      * @method initFrame
22804      */
22805     initFrame: function() {
22806         this.createFrame();
22807     },
22808
22809     applyConfig: function() {
22810         Roo.dd.DDProxy.superclass.applyConfig.call(this);
22811
22812         this.resizeFrame = (this.config.resizeFrame !== false);
22813         this.centerFrame = (this.config.centerFrame);
22814         this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
22815     },
22816
22817     /**
22818      * Resizes the drag frame to the dimensions of the clicked object, positions
22819      * it over the object, and finally displays it
22820      * @method showFrame
22821      * @param {int} iPageX X click position
22822      * @param {int} iPageY Y click position
22823      * @private
22824      */
22825     showFrame: function(iPageX, iPageY) {
22826         var el = this.getEl();
22827         var dragEl = this.getDragEl();
22828         var s = dragEl.style;
22829
22830         this._resizeProxy();
22831
22832         if (this.centerFrame) {
22833             this.setDelta( Math.round(parseInt(s.width,  10)/2),
22834                            Math.round(parseInt(s.height, 10)/2) );
22835         }
22836
22837         this.setDragElPos(iPageX, iPageY);
22838
22839         Roo.fly(dragEl).show();
22840     },
22841
22842     /**
22843      * The proxy is automatically resized to the dimensions of the linked
22844      * element when a drag is initiated, unless resizeFrame is set to false
22845      * @method _resizeProxy
22846      * @private
22847      */
22848     _resizeProxy: function() {
22849         if (this.resizeFrame) {
22850             var el = this.getEl();
22851             Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
22852         }
22853     },
22854
22855     // overrides Roo.dd.DragDrop
22856     b4MouseDown: function(e) {
22857         var x = e.getPageX();
22858         var y = e.getPageY();
22859         this.autoOffset(x, y);
22860         this.setDragElPos(x, y);
22861     },
22862
22863     // overrides Roo.dd.DragDrop
22864     b4StartDrag: function(x, y) {
22865         // show the drag frame
22866         this.showFrame(x, y);
22867     },
22868
22869     // overrides Roo.dd.DragDrop
22870     b4EndDrag: function(e) {
22871         Roo.fly(this.getDragEl()).hide();
22872     },
22873
22874     // overrides Roo.dd.DragDrop
22875     // By default we try to move the element to the last location of the frame.
22876     // This is so that the default behavior mirrors that of Roo.dd.DD.
22877     endDrag: function(e) {
22878
22879         var lel = this.getEl();
22880         var del = this.getDragEl();
22881
22882         // Show the drag frame briefly so we can get its position
22883         del.style.visibility = "";
22884
22885         this.beforeMove();
22886         // Hide the linked element before the move to get around a Safari
22887         // rendering bug.
22888         lel.style.visibility = "hidden";
22889         Roo.dd.DDM.moveToEl(lel, del);
22890         del.style.visibility = "hidden";
22891         lel.style.visibility = "";
22892
22893         this.afterDrag();
22894     },
22895
22896     beforeMove : function(){
22897
22898     },
22899
22900     afterDrag : function(){
22901
22902     },
22903
22904     toString: function() {
22905         return ("DDProxy " + this.id);
22906     }
22907
22908 });
22909 /*
22910  * Based on:
22911  * Ext JS Library 1.1.1
22912  * Copyright(c) 2006-2007, Ext JS, LLC.
22913  *
22914  * Originally Released Under LGPL - original licence link has changed is not relivant.
22915  *
22916  * Fork - LGPL
22917  * <script type="text/javascript">
22918  */
22919
22920  /**
22921  * @class Roo.dd.DDTarget
22922  * A DragDrop implementation that does not move, but can be a drop
22923  * target.  You would get the same result by simply omitting implementation
22924  * for the event callbacks, but this way we reduce the processing cost of the
22925  * event listener and the callbacks.
22926  * @extends Roo.dd.DragDrop
22927  * @constructor
22928  * @param {String} id the id of the element that is a drop target
22929  * @param {String} sGroup the group of related DragDrop objects
22930  * @param {object} config an object containing configurable attributes
22931  *                 Valid properties for DDTarget in addition to those in
22932  *                 DragDrop:
22933  *                    none
22934  */
22935 Roo.dd.DDTarget = function(id, sGroup, config) {
22936     if (id) {
22937         this.initTarget(id, sGroup, config);
22938     }
22939     if (config && (config.listeners || config.events)) { 
22940         Roo.dd.DragDrop.superclass.constructor.call(this,  { 
22941             listeners : config.listeners || {}, 
22942             events : config.events || {} 
22943         });    
22944     }
22945 };
22946
22947 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
22948 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
22949     toString: function() {
22950         return ("DDTarget " + this.id);
22951     }
22952 });
22953 /*
22954  * Based on:
22955  * Ext JS Library 1.1.1
22956  * Copyright(c) 2006-2007, Ext JS, LLC.
22957  *
22958  * Originally Released Under LGPL - original licence link has changed is not relivant.
22959  *
22960  * Fork - LGPL
22961  * <script type="text/javascript">
22962  */
22963  
22964
22965 /**
22966  * @class Roo.dd.ScrollManager
22967  * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
22968  * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
22969  * @static
22970  */
22971 Roo.dd.ScrollManager = function(){
22972     var ddm = Roo.dd.DragDropMgr;
22973     var els = {};
22974     var dragEl = null;
22975     var proc = {};
22976     
22977     
22978     
22979     var onStop = function(e){
22980         dragEl = null;
22981         clearProc();
22982     };
22983     
22984     var triggerRefresh = function(){
22985         if(ddm.dragCurrent){
22986              ddm.refreshCache(ddm.dragCurrent.groups);
22987         }
22988     };
22989     
22990     var doScroll = function(){
22991         if(ddm.dragCurrent){
22992             var dds = Roo.dd.ScrollManager;
22993             if(!dds.animate){
22994                 if(proc.el.scroll(proc.dir, dds.increment)){
22995                     triggerRefresh();
22996                 }
22997             }else{
22998                 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
22999             }
23000         }
23001     };
23002     
23003     var clearProc = function(){
23004         if(proc.id){
23005             clearInterval(proc.id);
23006         }
23007         proc.id = 0;
23008         proc.el = null;
23009         proc.dir = "";
23010     };
23011     
23012     var startProc = function(el, dir){
23013          Roo.log('scroll startproc');
23014         clearProc();
23015         proc.el = el;
23016         proc.dir = dir;
23017         proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
23018     };
23019     
23020     var onFire = function(e, isDrop){
23021        
23022         if(isDrop || !ddm.dragCurrent){ return; }
23023         var dds = Roo.dd.ScrollManager;
23024         if(!dragEl || dragEl != ddm.dragCurrent){
23025             dragEl = ddm.dragCurrent;
23026             // refresh regions on drag start
23027             dds.refreshCache();
23028         }
23029         
23030         var xy = Roo.lib.Event.getXY(e);
23031         var pt = new Roo.lib.Point(xy[0], xy[1]);
23032         for(var id in els){
23033             var el = els[id], r = el._region;
23034             if(r && r.contains(pt) && el.isScrollable()){
23035                 if(r.bottom - pt.y <= dds.thresh){
23036                     if(proc.el != el){
23037                         startProc(el, "down");
23038                     }
23039                     return;
23040                 }else if(r.right - pt.x <= dds.thresh){
23041                     if(proc.el != el){
23042                         startProc(el, "left");
23043                     }
23044                     return;
23045                 }else if(pt.y - r.top <= dds.thresh){
23046                     if(proc.el != el){
23047                         startProc(el, "up");
23048                     }
23049                     return;
23050                 }else if(pt.x - r.left <= dds.thresh){
23051                     if(proc.el != el){
23052                         startProc(el, "right");
23053                     }
23054                     return;
23055                 }
23056             }
23057         }
23058         clearProc();
23059     };
23060     
23061     ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
23062     ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
23063     
23064     return {
23065         /**
23066          * Registers new overflow element(s) to auto scroll
23067          * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
23068          */
23069         register : function(el){
23070             if(el instanceof Array){
23071                 for(var i = 0, len = el.length; i < len; i++) {
23072                         this.register(el[i]);
23073                 }
23074             }else{
23075                 el = Roo.get(el);
23076                 els[el.id] = el;
23077             }
23078             Roo.dd.ScrollManager.els = els;
23079         },
23080         
23081         /**
23082          * Unregisters overflow element(s) so they are no longer scrolled
23083          * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
23084          */
23085         unregister : function(el){
23086             if(el instanceof Array){
23087                 for(var i = 0, len = el.length; i < len; i++) {
23088                         this.unregister(el[i]);
23089                 }
23090             }else{
23091                 el = Roo.get(el);
23092                 delete els[el.id];
23093             }
23094         },
23095         
23096         /**
23097          * The number of pixels from the edge of a container the pointer needs to be to 
23098          * trigger scrolling (defaults to 25)
23099          * @type Number
23100          */
23101         thresh : 25,
23102         
23103         /**
23104          * The number of pixels to scroll in each scroll increment (defaults to 50)
23105          * @type Number
23106          */
23107         increment : 100,
23108         
23109         /**
23110          * The frequency of scrolls in milliseconds (defaults to 500)
23111          * @type Number
23112          */
23113         frequency : 500,
23114         
23115         /**
23116          * True to animate the scroll (defaults to true)
23117          * @type Boolean
23118          */
23119         animate: true,
23120         
23121         /**
23122          * The animation duration in seconds - 
23123          * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
23124          * @type Number
23125          */
23126         animDuration: .4,
23127         
23128         /**
23129          * Manually trigger a cache refresh.
23130          */
23131         refreshCache : function(){
23132             for(var id in els){
23133                 if(typeof els[id] == 'object'){ // for people extending the object prototype
23134                     els[id]._region = els[id].getRegion();
23135                 }
23136             }
23137         }
23138     };
23139 }();/*
23140  * Based on:
23141  * Ext JS Library 1.1.1
23142  * Copyright(c) 2006-2007, Ext JS, LLC.
23143  *
23144  * Originally Released Under LGPL - original licence link has changed is not relivant.
23145  *
23146  * Fork - LGPL
23147  * <script type="text/javascript">
23148  */
23149  
23150
23151 /**
23152  * @class Roo.dd.Registry
23153  * Provides easy access to all drag drop components that are registered on a page.  Items can be retrieved either
23154  * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
23155  * @static
23156  */
23157 Roo.dd.Registry = function(){
23158     var elements = {}; 
23159     var handles = {}; 
23160     var autoIdSeed = 0;
23161
23162     var getId = function(el, autogen){
23163         if(typeof el == "string"){
23164             return el;
23165         }
23166         var id = el.id;
23167         if(!id && autogen !== false){
23168             id = "roodd-" + (++autoIdSeed);
23169             el.id = id;
23170         }
23171         return id;
23172     };
23173     
23174     return {
23175     /**
23176      * Register a drag drop element
23177      * @param {String|HTMLElement} element The id or DOM node to register
23178      * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
23179      * in drag drop operations.  You can populate this object with any arbitrary properties that your own code
23180      * knows how to interpret, plus there are some specific properties known to the Registry that should be
23181      * populated in the data object (if applicable):
23182      * <pre>
23183 Value      Description<br />
23184 ---------  ------------------------------------------<br />
23185 handles    Array of DOM nodes that trigger dragging<br />
23186            for the element being registered<br />
23187 isHandle   True if the element passed in triggers<br />
23188            dragging itself, else false
23189 </pre>
23190      */
23191         register : function(el, data){
23192             data = data || {};
23193             if(typeof el == "string"){
23194                 el = document.getElementById(el);
23195             }
23196             data.ddel = el;
23197             elements[getId(el)] = data;
23198             if(data.isHandle !== false){
23199                 handles[data.ddel.id] = data;
23200             }
23201             if(data.handles){
23202                 var hs = data.handles;
23203                 for(var i = 0, len = hs.length; i < len; i++){
23204                         handles[getId(hs[i])] = data;
23205                 }
23206             }
23207         },
23208
23209     /**
23210      * Unregister a drag drop element
23211      * @param {String|HTMLElement}  element The id or DOM node to unregister
23212      */
23213         unregister : function(el){
23214             var id = getId(el, false);
23215             var data = elements[id];
23216             if(data){
23217                 delete elements[id];
23218                 if(data.handles){
23219                     var hs = data.handles;
23220                     for(var i = 0, len = hs.length; i < len; i++){
23221                         delete handles[getId(hs[i], false)];
23222                     }
23223                 }
23224             }
23225         },
23226
23227     /**
23228      * Returns the handle registered for a DOM Node by id
23229      * @param {String|HTMLElement} id The DOM node or id to look up
23230      * @return {Object} handle The custom handle data
23231      */
23232         getHandle : function(id){
23233             if(typeof id != "string"){ // must be element?
23234                 id = id.id;
23235             }
23236             return handles[id];
23237         },
23238
23239     /**
23240      * Returns the handle that is registered for the DOM node that is the target of the event
23241      * @param {Event} e The event
23242      * @return {Object} handle The custom handle data
23243      */
23244         getHandleFromEvent : function(e){
23245             var t = Roo.lib.Event.getTarget(e);
23246             return t ? handles[t.id] : null;
23247         },
23248
23249     /**
23250      * Returns a custom data object that is registered for a DOM node by id
23251      * @param {String|HTMLElement} id The DOM node or id to look up
23252      * @return {Object} data The custom data
23253      */
23254         getTarget : function(id){
23255             if(typeof id != "string"){ // must be element?
23256                 id = id.id;
23257             }
23258             return elements[id];
23259         },
23260
23261     /**
23262      * Returns a custom data object that is registered for the DOM node that is the target of the event
23263      * @param {Event} e The event
23264      * @return {Object} data The custom data
23265      */
23266         getTargetFromEvent : function(e){
23267             var t = Roo.lib.Event.getTarget(e);
23268             return t ? elements[t.id] || handles[t.id] : null;
23269         }
23270     };
23271 }();/*
23272  * Based on:
23273  * Ext JS Library 1.1.1
23274  * Copyright(c) 2006-2007, Ext JS, LLC.
23275  *
23276  * Originally Released Under LGPL - original licence link has changed is not relivant.
23277  *
23278  * Fork - LGPL
23279  * <script type="text/javascript">
23280  */
23281  
23282
23283 /**
23284  * @class Roo.dd.StatusProxy
23285  * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair.  This is the
23286  * default drag proxy used by all Roo.dd components.
23287  * @constructor
23288  * @param {Object} config
23289  */
23290 Roo.dd.StatusProxy = function(config){
23291     Roo.apply(this, config);
23292     this.id = this.id || Roo.id();
23293     this.el = new Roo.Layer({
23294         dh: {
23295             id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
23296                 {tag: "div", cls: "x-dd-drop-icon"},
23297                 {tag: "div", cls: "x-dd-drag-ghost"}
23298             ]
23299         }, 
23300         shadow: !config || config.shadow !== false
23301     });
23302     this.ghost = Roo.get(this.el.dom.childNodes[1]);
23303     this.dropStatus = this.dropNotAllowed;
23304 };
23305
23306 Roo.dd.StatusProxy.prototype = {
23307     /**
23308      * @cfg {String} dropAllowed
23309      * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
23310      */
23311     dropAllowed : "x-dd-drop-ok",
23312     /**
23313      * @cfg {String} dropNotAllowed
23314      * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
23315      */
23316     dropNotAllowed : "x-dd-drop-nodrop",
23317
23318     /**
23319      * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
23320      * over the current target element.
23321      * @param {String} cssClass The css class for the new drop status indicator image
23322      */
23323     setStatus : function(cssClass){
23324         cssClass = cssClass || this.dropNotAllowed;
23325         if(this.dropStatus != cssClass){
23326             this.el.replaceClass(this.dropStatus, cssClass);
23327             this.dropStatus = cssClass;
23328         }
23329     },
23330
23331     /**
23332      * Resets the status indicator to the default dropNotAllowed value
23333      * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
23334      */
23335     reset : function(clearGhost){
23336         this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
23337         this.dropStatus = this.dropNotAllowed;
23338         if(clearGhost){
23339             this.ghost.update("");
23340         }
23341     },
23342
23343     /**
23344      * Updates the contents of the ghost element
23345      * @param {String} html The html that will replace the current innerHTML of the ghost element
23346      */
23347     update : function(html){
23348         if(typeof html == "string"){
23349             this.ghost.update(html);
23350         }else{
23351             this.ghost.update("");
23352             html.style.margin = "0";
23353             this.ghost.dom.appendChild(html);
23354         }
23355         // ensure float = none set?? cant remember why though.
23356         var el = this.ghost.dom.firstChild;
23357                 if(el){
23358                         Roo.fly(el).setStyle('float', 'none');
23359                 }
23360     },
23361     
23362     /**
23363      * Returns the underlying proxy {@link Roo.Layer}
23364      * @return {Roo.Layer} el
23365     */
23366     getEl : function(){
23367         return this.el;
23368     },
23369
23370     /**
23371      * Returns the ghost element
23372      * @return {Roo.Element} el
23373      */
23374     getGhost : function(){
23375         return this.ghost;
23376     },
23377
23378     /**
23379      * Hides the proxy
23380      * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
23381      */
23382     hide : function(clear){
23383         this.el.hide();
23384         if(clear){
23385             this.reset(true);
23386         }
23387     },
23388
23389     /**
23390      * Stops the repair animation if it's currently running
23391      */
23392     stop : function(){
23393         if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
23394             this.anim.stop();
23395         }
23396     },
23397
23398     /**
23399      * Displays this proxy
23400      */
23401     show : function(){
23402         this.el.show();
23403     },
23404
23405     /**
23406      * Force the Layer to sync its shadow and shim positions to the element
23407      */
23408     sync : function(){
23409         this.el.sync();
23410     },
23411
23412     /**
23413      * Causes the proxy to return to its position of origin via an animation.  Should be called after an
23414      * invalid drop operation by the item being dragged.
23415      * @param {Array} xy The XY position of the element ([x, y])
23416      * @param {Function} callback The function to call after the repair is complete
23417      * @param {Object} scope The scope in which to execute the callback
23418      */
23419     repair : function(xy, callback, scope){
23420         this.callback = callback;
23421         this.scope = scope;
23422         if(xy && this.animRepair !== false){
23423             this.el.addClass("x-dd-drag-repair");
23424             this.el.hideUnders(true);
23425             this.anim = this.el.shift({
23426                 duration: this.repairDuration || .5,
23427                 easing: 'easeOut',
23428                 xy: xy,
23429                 stopFx: true,
23430                 callback: this.afterRepair,
23431                 scope: this
23432             });
23433         }else{
23434             this.afterRepair();
23435         }
23436     },
23437
23438     // private
23439     afterRepair : function(){
23440         this.hide(true);
23441         if(typeof this.callback == "function"){
23442             this.callback.call(this.scope || this);
23443         }
23444         this.callback = null;
23445         this.scope = null;
23446     }
23447 };/*
23448  * Based on:
23449  * Ext JS Library 1.1.1
23450  * Copyright(c) 2006-2007, Ext JS, LLC.
23451  *
23452  * Originally Released Under LGPL - original licence link has changed is not relivant.
23453  *
23454  * Fork - LGPL
23455  * <script type="text/javascript">
23456  */
23457
23458 /**
23459  * @class Roo.dd.DragSource
23460  * @extends Roo.dd.DDProxy
23461  * A simple class that provides the basic implementation needed to make any element draggable.
23462  * @constructor
23463  * @param {String/HTMLElement/Element} el The container element
23464  * @param {Object} config
23465  */
23466 Roo.dd.DragSource = function(el, config){
23467     this.el = Roo.get(el);
23468     this.dragData = {};
23469     
23470     Roo.apply(this, config);
23471     
23472     if(!this.proxy){
23473         this.proxy = new Roo.dd.StatusProxy();
23474     }
23475
23476     Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
23477           {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
23478     
23479     this.dragging = false;
23480 };
23481
23482 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
23483     /**
23484      * @cfg {String} dropAllowed
23485      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
23486      */
23487     dropAllowed : "x-dd-drop-ok",
23488     /**
23489      * @cfg {String} dropNotAllowed
23490      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
23491      */
23492     dropNotAllowed : "x-dd-drop-nodrop",
23493
23494     /**
23495      * Returns the data object associated with this drag source
23496      * @return {Object} data An object containing arbitrary data
23497      */
23498     getDragData : function(e){
23499         return this.dragData;
23500     },
23501
23502     // private
23503     onDragEnter : function(e, id){
23504         var target = Roo.dd.DragDropMgr.getDDById(id);
23505         this.cachedTarget = target;
23506         if(this.beforeDragEnter(target, e, id) !== false){
23507             if(target.isNotifyTarget){
23508                 var status = target.notifyEnter(this, e, this.dragData);
23509                 this.proxy.setStatus(status);
23510             }else{
23511                 this.proxy.setStatus(this.dropAllowed);
23512             }
23513             
23514             if(this.afterDragEnter){
23515                 /**
23516                  * An empty function by default, but provided so that you can perform a custom action
23517                  * when the dragged item enters the drop target by providing an implementation.
23518                  * @param {Roo.dd.DragDrop} target The drop target
23519                  * @param {Event} e The event object
23520                  * @param {String} id The id of the dragged element
23521                  * @method afterDragEnter
23522                  */
23523                 this.afterDragEnter(target, e, id);
23524             }
23525         }
23526     },
23527
23528     /**
23529      * An empty function by default, but provided so that you can perform a custom action
23530      * before the dragged item enters the drop target and optionally cancel the onDragEnter.
23531      * @param {Roo.dd.DragDrop} target The drop target
23532      * @param {Event} e The event object
23533      * @param {String} id The id of the dragged element
23534      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23535      */
23536     beforeDragEnter : function(target, e, id){
23537         return true;
23538     },
23539
23540     // private
23541     alignElWithMouse: function() {
23542         Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
23543         this.proxy.sync();
23544     },
23545
23546     // private
23547     onDragOver : function(e, id){
23548         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23549         if(this.beforeDragOver(target, e, id) !== false){
23550             if(target.isNotifyTarget){
23551                 var status = target.notifyOver(this, e, this.dragData);
23552                 this.proxy.setStatus(status);
23553             }
23554
23555             if(this.afterDragOver){
23556                 /**
23557                  * An empty function by default, but provided so that you can perform a custom action
23558                  * while the dragged item is over the drop target by providing an implementation.
23559                  * @param {Roo.dd.DragDrop} target The drop target
23560                  * @param {Event} e The event object
23561                  * @param {String} id The id of the dragged element
23562                  * @method afterDragOver
23563                  */
23564                 this.afterDragOver(target, e, id);
23565             }
23566         }
23567     },
23568
23569     /**
23570      * An empty function by default, but provided so that you can perform a custom action
23571      * while the dragged item is over the drop target and optionally cancel the onDragOver.
23572      * @param {Roo.dd.DragDrop} target The drop target
23573      * @param {Event} e The event object
23574      * @param {String} id The id of the dragged element
23575      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23576      */
23577     beforeDragOver : function(target, e, id){
23578         return true;
23579     },
23580
23581     // private
23582     onDragOut : function(e, id){
23583         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23584         if(this.beforeDragOut(target, e, id) !== false){
23585             if(target.isNotifyTarget){
23586                 target.notifyOut(this, e, this.dragData);
23587             }
23588             this.proxy.reset();
23589             if(this.afterDragOut){
23590                 /**
23591                  * An empty function by default, but provided so that you can perform a custom action
23592                  * after the dragged item is dragged out of the target without dropping.
23593                  * @param {Roo.dd.DragDrop} target The drop target
23594                  * @param {Event} e The event object
23595                  * @param {String} id The id of the dragged element
23596                  * @method afterDragOut
23597                  */
23598                 this.afterDragOut(target, e, id);
23599             }
23600         }
23601         this.cachedTarget = null;
23602     },
23603
23604     /**
23605      * An empty function by default, but provided so that you can perform a custom action before the dragged
23606      * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
23607      * @param {Roo.dd.DragDrop} target The drop target
23608      * @param {Event} e The event object
23609      * @param {String} id The id of the dragged element
23610      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23611      */
23612     beforeDragOut : function(target, e, id){
23613         return true;
23614     },
23615     
23616     // private
23617     onDragDrop : function(e, id){
23618         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23619         if(this.beforeDragDrop(target, e, id) !== false){
23620             if(target.isNotifyTarget){
23621                 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
23622                     this.onValidDrop(target, e, id);
23623                 }else{
23624                     this.onInvalidDrop(target, e, id);
23625                 }
23626             }else{
23627                 this.onValidDrop(target, e, id);
23628             }
23629             
23630             if(this.afterDragDrop){
23631                 /**
23632                  * An empty function by default, but provided so that you can perform a custom action
23633                  * after a valid drag drop has occurred by providing an implementation.
23634                  * @param {Roo.dd.DragDrop} target The drop target
23635                  * @param {Event} e The event object
23636                  * @param {String} id The id of the dropped element
23637                  * @method afterDragDrop
23638                  */
23639                 this.afterDragDrop(target, e, id);
23640             }
23641         }
23642         delete this.cachedTarget;
23643     },
23644
23645     /**
23646      * An empty function by default, but provided so that you can perform a custom action before the dragged
23647      * item is dropped onto the target and optionally cancel the onDragDrop.
23648      * @param {Roo.dd.DragDrop} target The drop target
23649      * @param {Event} e The event object
23650      * @param {String} id The id of the dragged element
23651      * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
23652      */
23653     beforeDragDrop : function(target, e, id){
23654         return true;
23655     },
23656
23657     // private
23658     onValidDrop : function(target, e, id){
23659         this.hideProxy();
23660         if(this.afterValidDrop){
23661             /**
23662              * An empty function by default, but provided so that you can perform a custom action
23663              * after a valid drop has occurred by providing an implementation.
23664              * @param {Object} target The target DD 
23665              * @param {Event} e The event object
23666              * @param {String} id The id of the dropped element
23667              * @method afterInvalidDrop
23668              */
23669             this.afterValidDrop(target, e, id);
23670         }
23671     },
23672
23673     // private
23674     getRepairXY : function(e, data){
23675         return this.el.getXY();  
23676     },
23677
23678     // private
23679     onInvalidDrop : function(target, e, id){
23680         this.beforeInvalidDrop(target, e, id);
23681         if(this.cachedTarget){
23682             if(this.cachedTarget.isNotifyTarget){
23683                 this.cachedTarget.notifyOut(this, e, this.dragData);
23684             }
23685             this.cacheTarget = null;
23686         }
23687         this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
23688
23689         if(this.afterInvalidDrop){
23690             /**
23691              * An empty function by default, but provided so that you can perform a custom action
23692              * after an invalid drop has occurred by providing an implementation.
23693              * @param {Event} e The event object
23694              * @param {String} id The id of the dropped element
23695              * @method afterInvalidDrop
23696              */
23697             this.afterInvalidDrop(e, id);
23698         }
23699     },
23700
23701     // private
23702     afterRepair : function(){
23703         if(Roo.enableFx){
23704             this.el.highlight(this.hlColor || "c3daf9");
23705         }
23706         this.dragging = false;
23707     },
23708
23709     /**
23710      * An empty function by default, but provided so that you can perform a custom action after an invalid
23711      * drop has occurred.
23712      * @param {Roo.dd.DragDrop} target The drop target
23713      * @param {Event} e The event object
23714      * @param {String} id The id of the dragged element
23715      * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
23716      */
23717     beforeInvalidDrop : function(target, e, id){
23718         return true;
23719     },
23720
23721     // private
23722     handleMouseDown : function(e){
23723         if(this.dragging) {
23724             return;
23725         }
23726         var data = this.getDragData(e);
23727         if(data && this.onBeforeDrag(data, e) !== false){
23728             this.dragData = data;
23729             this.proxy.stop();
23730             Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
23731         } 
23732     },
23733
23734     /**
23735      * An empty function by default, but provided so that you can perform a custom action before the initial
23736      * drag event begins and optionally cancel it.
23737      * @param {Object} data An object containing arbitrary data to be shared with drop targets
23738      * @param {Event} e The event object
23739      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23740      */
23741     onBeforeDrag : function(data, e){
23742         return true;
23743     },
23744
23745     /**
23746      * An empty function by default, but provided so that you can perform a custom action once the initial
23747      * drag event has begun.  The drag cannot be canceled from this function.
23748      * @param {Number} x The x position of the click on the dragged object
23749      * @param {Number} y The y position of the click on the dragged object
23750      */
23751     onStartDrag : Roo.emptyFn,
23752
23753     // private - YUI override
23754     startDrag : function(x, y){
23755         this.proxy.reset();
23756         this.dragging = true;
23757         this.proxy.update("");
23758         this.onInitDrag(x, y);
23759         this.proxy.show();
23760     },
23761
23762     // private
23763     onInitDrag : function(x, y){
23764         var clone = this.el.dom.cloneNode(true);
23765         clone.id = Roo.id(); // prevent duplicate ids
23766         this.proxy.update(clone);
23767         this.onStartDrag(x, y);
23768         return true;
23769     },
23770
23771     /**
23772      * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
23773      * @return {Roo.dd.StatusProxy} proxy The StatusProxy
23774      */
23775     getProxy : function(){
23776         return this.proxy;  
23777     },
23778
23779     /**
23780      * Hides the drag source's {@link Roo.dd.StatusProxy}
23781      */
23782     hideProxy : function(){
23783         this.proxy.hide();  
23784         this.proxy.reset(true);
23785         this.dragging = false;
23786     },
23787
23788     // private
23789     triggerCacheRefresh : function(){
23790         Roo.dd.DDM.refreshCache(this.groups);
23791     },
23792
23793     // private - override to prevent hiding
23794     b4EndDrag: function(e) {
23795     },
23796
23797     // private - override to prevent moving
23798     endDrag : function(e){
23799         this.onEndDrag(this.dragData, e);
23800     },
23801
23802     // private
23803     onEndDrag : function(data, e){
23804     },
23805     
23806     // private - pin to cursor
23807     autoOffset : function(x, y) {
23808         this.setDelta(-12, -20);
23809     }    
23810 });/*
23811  * Based on:
23812  * Ext JS Library 1.1.1
23813  * Copyright(c) 2006-2007, Ext JS, LLC.
23814  *
23815  * Originally Released Under LGPL - original licence link has changed is not relivant.
23816  *
23817  * Fork - LGPL
23818  * <script type="text/javascript">
23819  */
23820
23821
23822 /**
23823  * @class Roo.dd.DropTarget
23824  * @extends Roo.dd.DDTarget
23825  * A simple class that provides the basic implementation needed to make any element a drop target that can have
23826  * draggable items dropped onto it.  The drop has no effect until an implementation of notifyDrop is provided.
23827  * @constructor
23828  * @param {String/HTMLElement/Element} el The container element
23829  * @param {Object} config
23830  */
23831 Roo.dd.DropTarget = function(el, config){
23832     this.el = Roo.get(el);
23833     
23834     var listeners = false; ;
23835     if (config && config.listeners) {
23836         listeners= config.listeners;
23837         delete config.listeners;
23838     }
23839     Roo.apply(this, config);
23840     
23841     if(this.containerScroll){
23842         Roo.dd.ScrollManager.register(this.el);
23843     }
23844     this.addEvents( {
23845          /**
23846          * @scope Roo.dd.DropTarget
23847          */
23848          
23849          /**
23850          * @event enter
23851          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
23852          * target.  This default implementation adds the CSS class specified by overClass (if any) to the drop element
23853          * and returns the dropAllowed config value.  This method should be overridden if drop validation is required.
23854          * 
23855          * IMPORTANT : it should set  this.valid to true|false
23856          * 
23857          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23858          * @param {Event} e The event
23859          * @param {Object} data An object containing arbitrary data supplied by the drag source
23860          */
23861         "enter" : true,
23862         
23863          /**
23864          * @event over
23865          * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
23866          * This method will be called on every mouse movement while the drag source is over the drop target.
23867          * This default implementation simply returns the dropAllowed config value.
23868          * 
23869          * IMPORTANT : it should set  this.valid to true|false
23870          * 
23871          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23872          * @param {Event} e The event
23873          * @param {Object} data An object containing arbitrary data supplied by the drag source
23874          
23875          */
23876         "over" : true,
23877         /**
23878          * @event out
23879          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
23880          * out of the target without dropping.  This default implementation simply removes the CSS class specified by
23881          * overClass (if any) from the drop element.
23882          * 
23883          * 
23884          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23885          * @param {Event} e The event
23886          * @param {Object} data An object containing arbitrary data supplied by the drag source
23887          */
23888          "out" : true,
23889          
23890         /**
23891          * @event drop
23892          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
23893          * been dropped on it.  This method has no default implementation and returns false, so you must provide an
23894          * implementation that does something to process the drop event and returns true so that the drag source's
23895          * repair action does not run.
23896          * 
23897          * IMPORTANT : it should set this.success
23898          * 
23899          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23900          * @param {Event} e The event
23901          * @param {Object} data An object containing arbitrary data supplied by the drag source
23902         */
23903          "drop" : true
23904     });
23905             
23906      
23907     Roo.dd.DropTarget.superclass.constructor.call(  this, 
23908         this.el.dom, 
23909         this.ddGroup || this.group,
23910         {
23911             isTarget: true,
23912             listeners : listeners || {} 
23913            
23914         
23915         }
23916     );
23917
23918 };
23919
23920 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
23921     /**
23922      * @cfg {String} overClass
23923      * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
23924      */
23925      /**
23926      * @cfg {String} ddGroup
23927      * The drag drop group to handle drop events for
23928      */
23929      
23930     /**
23931      * @cfg {String} dropAllowed
23932      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
23933      */
23934     dropAllowed : "x-dd-drop-ok",
23935     /**
23936      * @cfg {String} dropNotAllowed
23937      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
23938      */
23939     dropNotAllowed : "x-dd-drop-nodrop",
23940     /**
23941      * @cfg {boolean} success
23942      * set this after drop listener.. 
23943      */
23944     success : false,
23945     /**
23946      * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
23947      * if the drop point is valid for over/enter..
23948      */
23949     valid : false,
23950     // private
23951     isTarget : true,
23952
23953     // private
23954     isNotifyTarget : true,
23955     
23956     /**
23957      * @hide
23958      */
23959     notifyEnter : function(dd, e, data)
23960     {
23961         this.valid = true;
23962         this.fireEvent('enter', dd, e, data);
23963         if(this.overClass){
23964             this.el.addClass(this.overClass);
23965         }
23966         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
23967             this.valid ? this.dropAllowed : this.dropNotAllowed
23968         );
23969     },
23970
23971     /**
23972      * @hide
23973      */
23974     notifyOver : function(dd, e, data)
23975     {
23976         this.valid = true;
23977         this.fireEvent('over', dd, e, data);
23978         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
23979             this.valid ? this.dropAllowed : this.dropNotAllowed
23980         );
23981     },
23982
23983     /**
23984      * @hide
23985      */
23986     notifyOut : function(dd, e, data)
23987     {
23988         this.fireEvent('out', dd, e, data);
23989         if(this.overClass){
23990             this.el.removeClass(this.overClass);
23991         }
23992     },
23993
23994     /**
23995      * @hide
23996      */
23997     notifyDrop : function(dd, e, data)
23998     {
23999         this.success = false;
24000         this.fireEvent('drop', dd, e, data);
24001         return this.success;
24002     }
24003 });/*
24004  * Based on:
24005  * Ext JS Library 1.1.1
24006  * Copyright(c) 2006-2007, Ext JS, LLC.
24007  *
24008  * Originally Released Under LGPL - original licence link has changed is not relivant.
24009  *
24010  * Fork - LGPL
24011  * <script type="text/javascript">
24012  */
24013
24014
24015 /**
24016  * @class Roo.dd.DragZone
24017  * @extends Roo.dd.DragSource
24018  * This class provides a container DD instance that proxies for multiple child node sources.<br />
24019  * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
24020  * @constructor
24021  * @param {String/HTMLElement/Element} el The container element
24022  * @param {Object} config
24023  */
24024 Roo.dd.DragZone = function(el, config){
24025     Roo.dd.DragZone.superclass.constructor.call(this, el, config);
24026     if(this.containerScroll){
24027         Roo.dd.ScrollManager.register(this.el);
24028     }
24029 };
24030
24031 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
24032     /**
24033      * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
24034      * for auto scrolling during drag operations.
24035      */
24036     /**
24037      * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
24038      * method after a failed drop (defaults to "c3daf9" - light blue)
24039      */
24040
24041     /**
24042      * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
24043      * for a valid target to drag based on the mouse down. Override this method
24044      * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
24045      * object has a "ddel" attribute (with an HTML Element) for other functions to work.
24046      * @param {EventObject} e The mouse down event
24047      * @return {Object} The dragData
24048      */
24049     getDragData : function(e){
24050         return Roo.dd.Registry.getHandleFromEvent(e);
24051     },
24052     
24053     /**
24054      * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
24055      * this.dragData.ddel
24056      * @param {Number} x The x position of the click on the dragged object
24057      * @param {Number} y The y position of the click on the dragged object
24058      * @return {Boolean} true to continue the drag, false to cancel
24059      */
24060     onInitDrag : function(x, y){
24061         this.proxy.update(this.dragData.ddel.cloneNode(true));
24062         this.onStartDrag(x, y);
24063         return true;
24064     },
24065     
24066     /**
24067      * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel 
24068      */
24069     afterRepair : function(){
24070         if(Roo.enableFx){
24071             Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
24072         }
24073         this.dragging = false;
24074     },
24075
24076     /**
24077      * Called before a repair of an invalid drop to get the XY to animate to. By default returns
24078      * the XY of this.dragData.ddel
24079      * @param {EventObject} e The mouse up event
24080      * @return {Array} The xy location (e.g. [100, 200])
24081      */
24082     getRepairXY : function(e){
24083         return Roo.Element.fly(this.dragData.ddel).getXY();  
24084     }
24085 });/*
24086  * Based on:
24087  * Ext JS Library 1.1.1
24088  * Copyright(c) 2006-2007, Ext JS, LLC.
24089  *
24090  * Originally Released Under LGPL - original licence link has changed is not relivant.
24091  *
24092  * Fork - LGPL
24093  * <script type="text/javascript">
24094  */
24095 /**
24096  * @class Roo.dd.DropZone
24097  * @extends Roo.dd.DropTarget
24098  * This class provides a container DD instance that proxies for multiple child node targets.<br />
24099  * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
24100  * @constructor
24101  * @param {String/HTMLElement/Element} el The container element
24102  * @param {Object} config
24103  */
24104 Roo.dd.DropZone = function(el, config){
24105     Roo.dd.DropZone.superclass.constructor.call(this, el, config);
24106 };
24107
24108 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
24109     /**
24110      * Returns a custom data object associated with the DOM node that is the target of the event.  By default
24111      * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
24112      * provide your own custom lookup.
24113      * @param {Event} e The event
24114      * @return {Object} data The custom data
24115      */
24116     getTargetFromEvent : function(e){
24117         return Roo.dd.Registry.getTargetFromEvent(e);
24118     },
24119
24120     /**
24121      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
24122      * that it has registered.  This method has no default implementation and should be overridden to provide
24123      * node-specific processing if necessary.
24124      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from 
24125      * {@link #getTargetFromEvent} for this node)
24126      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24127      * @param {Event} e The event
24128      * @param {Object} data An object containing arbitrary data supplied by the drag source
24129      */
24130     onNodeEnter : function(n, dd, e, data){
24131         
24132     },
24133
24134     /**
24135      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
24136      * that it has registered.  The default implementation returns this.dropNotAllowed, so it should be
24137      * overridden to provide the proper feedback.
24138      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
24139      * {@link #getTargetFromEvent} for this node)
24140      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24141      * @param {Event} e The event
24142      * @param {Object} data An object containing arbitrary data supplied by the drag source
24143      * @return {String} status The CSS class that communicates the drop status back to the source so that the
24144      * underlying {@link Roo.dd.StatusProxy} can be updated
24145      */
24146     onNodeOver : function(n, dd, e, data){
24147         return this.dropAllowed;
24148     },
24149
24150     /**
24151      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
24152      * the drop node without dropping.  This method has no default implementation and should be overridden to provide
24153      * node-specific processing if necessary.
24154      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
24155      * {@link #getTargetFromEvent} for this node)
24156      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24157      * @param {Event} e The event
24158      * @param {Object} data An object containing arbitrary data supplied by the drag source
24159      */
24160     onNodeOut : function(n, dd, e, data){
24161         
24162     },
24163
24164     /**
24165      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
24166      * the drop node.  The default implementation returns false, so it should be overridden to provide the
24167      * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
24168      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
24169      * {@link #getTargetFromEvent} for this node)
24170      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24171      * @param {Event} e The event
24172      * @param {Object} data An object containing arbitrary data supplied by the drag source
24173      * @return {Boolean} True if the drop was valid, else false
24174      */
24175     onNodeDrop : function(n, dd, e, data){
24176         return false;
24177     },
24178
24179     /**
24180      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
24181      * but not over any of its registered drop nodes.  The default implementation returns this.dropNotAllowed, so
24182      * it should be overridden to provide the proper feedback if necessary.
24183      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24184      * @param {Event} e The event
24185      * @param {Object} data An object containing arbitrary data supplied by the drag source
24186      * @return {String} status The CSS class that communicates the drop status back to the source so that the
24187      * underlying {@link Roo.dd.StatusProxy} can be updated
24188      */
24189     onContainerOver : function(dd, e, data){
24190         return this.dropNotAllowed;
24191     },
24192
24193     /**
24194      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
24195      * but not on any of its registered drop nodes.  The default implementation returns false, so it should be
24196      * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
24197      * be able to accept drops.  It should return true when valid so that the drag source's repair action does not run.
24198      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24199      * @param {Event} e The event
24200      * @param {Object} data An object containing arbitrary data supplied by the drag source
24201      * @return {Boolean} True if the drop was valid, else false
24202      */
24203     onContainerDrop : function(dd, e, data){
24204         return false;
24205     },
24206
24207     /**
24208      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
24209      * the zone.  The default implementation returns this.dropNotAllowed and expects that only registered drop
24210      * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
24211      * you should override this method and provide a custom implementation.
24212      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24213      * @param {Event} e The event
24214      * @param {Object} data An object containing arbitrary data supplied by the drag source
24215      * @return {String} status The CSS class that communicates the drop status back to the source so that the
24216      * underlying {@link Roo.dd.StatusProxy} can be updated
24217      */
24218     notifyEnter : function(dd, e, data){
24219         return this.dropNotAllowed;
24220     },
24221
24222     /**
24223      * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
24224      * This method will be called on every mouse movement while the drag source is over the drop zone.
24225      * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
24226      * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
24227      * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
24228      * registered node, it will call {@link #onContainerOver}.
24229      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24230      * @param {Event} e The event
24231      * @param {Object} data An object containing arbitrary data supplied by the drag source
24232      * @return {String} status The CSS class that communicates the drop status back to the source so that the
24233      * underlying {@link Roo.dd.StatusProxy} can be updated
24234      */
24235     notifyOver : function(dd, e, data){
24236         var n = this.getTargetFromEvent(e);
24237         if(!n){ // not over valid drop target
24238             if(this.lastOverNode){
24239                 this.onNodeOut(this.lastOverNode, dd, e, data);
24240                 this.lastOverNode = null;
24241             }
24242             return this.onContainerOver(dd, e, data);
24243         }
24244         if(this.lastOverNode != n){
24245             if(this.lastOverNode){
24246                 this.onNodeOut(this.lastOverNode, dd, e, data);
24247             }
24248             this.onNodeEnter(n, dd, e, data);
24249             this.lastOverNode = n;
24250         }
24251         return this.onNodeOver(n, dd, e, data);
24252     },
24253
24254     /**
24255      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
24256      * out of the zone without dropping.  If the drag source is currently over a registered node, the notification
24257      * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
24258      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
24259      * @param {Event} e The event
24260      * @param {Object} data An object containing arbitrary data supplied by the drag zone
24261      */
24262     notifyOut : function(dd, e, data){
24263         if(this.lastOverNode){
24264             this.onNodeOut(this.lastOverNode, dd, e, data);
24265             this.lastOverNode = null;
24266         }
24267     },
24268
24269     /**
24270      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
24271      * been dropped on it.  The drag zone will look up the target node based on the event passed in, and if there
24272      * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
24273      * otherwise it will call {@link #onContainerDrop}.
24274      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24275      * @param {Event} e The event
24276      * @param {Object} data An object containing arbitrary data supplied by the drag source
24277      * @return {Boolean} True if the drop was valid, else false
24278      */
24279     notifyDrop : function(dd, e, data){
24280         if(this.lastOverNode){
24281             this.onNodeOut(this.lastOverNode, dd, e, data);
24282             this.lastOverNode = null;
24283         }
24284         var n = this.getTargetFromEvent(e);
24285         return n ?
24286             this.onNodeDrop(n, dd, e, data) :
24287             this.onContainerDrop(dd, e, data);
24288     },
24289
24290     // private
24291     triggerCacheRefresh : function(){
24292         Roo.dd.DDM.refreshCache(this.groups);
24293     }  
24294 });